From 7d8929f9f5a91d9fc9c8a8f3975bfa1a95f3a562 Mon Sep 17 00:00:00 2001 From: Ryan Keairns Date: Tue, 3 Mar 2020 16:23:07 -0600 Subject: [PATCH] add EuiSkipLink component --- CHANGELOG.md | 2 + .../accessibility/accessibility_example.js | 65 +++++++++++++++---- .../src/views/accessibility/screen_reader.tsx | 14 ++-- .../src/views/accessibility/skip_link.tsx | 34 ++++++++++ src/components/accessibility/_index.scss | 1 + src/components/accessibility/_skip_link.scss | 18 +++++ src/components/accessibility/index.ts | 1 + src/components/accessibility/skip_link.tsx | 34 ++++++++++ src/components/index.js | 6 +- 9 files changed, 155 insertions(+), 20 deletions(-) create mode 100644 src-docs/src/views/accessibility/skip_link.tsx create mode 100644 src/components/accessibility/_skip_link.scss create mode 100644 src/components/accessibility/skip_link.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index 4035559c5d39..1d1320af2fd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## [`master`](https://github.com/elastic/eui/tree/master) +- Added `showOnFocus` prop to `EuiScreenReaderOnly` to force display on keyboard focus ([#2976](https://github.com/elastic/eui/pull/2976)) +- Added `EuiSkipLink` component ([#2976](https://github.com/elastic/eui/pull/2976)) - `EuiButton` now has a single return statement ([#2954](https://github.com/elastic/eui/pull/2954)) - Added `isSortable` props to `EuiDataGridColumn` and `EuiDataGridSchemaDetector` to mark them as un-sortable ([#2952](https://github.com/elastic/eui/pull/2952)) - Converted `EuiForm` to TypeScript, added many missing `/form` Prop types ([#2896](https://github.com/elastic/eui/pull/2896)) diff --git a/src-docs/src/views/accessibility/accessibility_example.js b/src-docs/src/views/accessibility/accessibility_example.js index 642a2c2f7391..6f71a70c1494 100644 --- a/src-docs/src/views/accessibility/accessibility_example.js +++ b/src-docs/src/views/accessibility/accessibility_example.js @@ -5,13 +5,16 @@ import { renderToHtml } from '../../services'; import { GuideSectionTypes } from '../../components'; import { + EuiCallOut, EuiCode, EuiLink, EuiKeyboardAccessible, + EuiSkipLink, } from '../../../../src/components'; import KeyboardAccessible from './keyboard_accessible'; import ScreenReaderOnly from './screen_reader'; +import SkipLink from './skip_link'; const keyboardAccessibleSource = require('!!raw-loader!./keyboard_accessible'); const keyboardAccessibleHtml = renderToHtml(KeyboardAccessible); @@ -19,13 +22,16 @@ const keyboardAccessibleHtml = renderToHtml(KeyboardAccessible); const screenReaderOnlyHtml = renderToHtml(ScreenReaderOnly); const screenReaderOnlySource = require('!!raw-loader!./screen_reader'); +const skipLinkHtml = renderToHtml(SkipLink); +const skipLinkSource = require('!!raw-loader!./skip_link'); + import { ScreenReaderOnlyDocsComponent } from './props'; export const AccessibilityExample = { title: 'Accessibility', sections: [ { - title: 'KeyboardAccessible', + title: 'Keyboard accessible', source: [ { type: GuideSectionTypes.JS, @@ -38,9 +44,9 @@ export const AccessibilityExample = { ], text: (

- You can make interactive elements keyboard-accessible with this - component. This is necessary for non-button elements and{' '} - a tags without + You can make interactive elements keyboard-accessible with the{' '} + EuiKeyboardAccessible component. This is necessary + for non-button elements and a tags without{' '} href attributes.

), @@ -48,7 +54,7 @@ export const AccessibilityExample = { demo: , }, { - title: 'ScreenReaderOnly', + title: 'Screen reader only', source: [ { type: GuideSectionTypes.JS, @@ -62,20 +68,51 @@ export const AccessibilityExample = { text: (

- This class can be useful to add accessibility to older designs that - are still in use, but it shouldn’t be a permanent solution. - See{' '} - { + Use the EuiScreenReaderOnly component to visually + hide elements while still allowing them to be read by screen + readers. +

+ +

+ In most cases, if content (particularly content that provides + functionality or interactivity) is important enough to provide to + screen reader users, it should probably be made available to all + users.{' '} - http://webaim.org/techniques/css/invisiblecontent/ + Learn more - }{' '} - for more information. -

+

+
), - props: { EuiScreenReaderOnly: ScreenReaderOnlyDocsComponent }, + props: { + EuiScreenReaderOnly: ScreenReaderOnlyDocsComponent, + }, demo: , }, + { + title: 'Skip to main content', + source: [ + { + type: GuideSectionTypes.JS, + code: skipLinkSource, + }, + { + type: GuideSectionTypes.HTML, + code: skipLinkHtml, + }, + ], + text: ( +

+ The EuiSkipLink component allows users to bypass + navigation and quickly reach the main content of the page. +

+ ), + props: { EuiSkipLink }, + demo: , + }, ], }; diff --git a/src-docs/src/views/accessibility/screen_reader.tsx b/src-docs/src/views/accessibility/screen_reader.tsx index e8ce8dc3281b..80d0023121f3 100644 --- a/src-docs/src/views/accessibility/screen_reader.tsx +++ b/src-docs/src/views/accessibility/screen_reader.tsx @@ -8,6 +8,9 @@ import { EuiTitle } from '../../../../src/components/title'; export default () => (
+ +

Visually hide content

+

Use a screenreader to verify that there is a second paragraph in this @@ -27,16 +30,17 @@ export default () => (

- In certain cases, such as a Skip to content link, you - can use the showOnFocus prop to display - screenreader content upon focus. For example, tabbing to this section - with your keyboard will display a link. + In certain cases, you may want to display screen reader-only content + when it is in focus. This can be accoplished by adding the{' '} + showOnFocus prop. For example, tabbing through this + section with your keyboard will display a ‘Skip to content + ’ link:

This link is visible to all on focus:{' '} - Skip content + Skip to content

diff --git a/src-docs/src/views/accessibility/skip_link.tsx b/src-docs/src/views/accessibility/skip_link.tsx new file mode 100644 index 000000000000..f967e9b88bf2 --- /dev/null +++ b/src-docs/src/views/accessibility/skip_link.tsx @@ -0,0 +1,34 @@ +import React from 'react'; + +import { EuiSkipLink } from '../../../../src/components/accessibility/skip_link'; +import { EuiCallOut } from '../../../../src/components/call_out'; +import { EuiText } from '../../../../src/components/text'; +import { EuiPortal } from '../../../../src/components/portal'; + +export default () => ( +
+ +

+ + Tab out of the browser's address bar and a{' '} + Skip to main content link will appear on this page. + +

+ +
+ + + +
+); diff --git a/src/components/accessibility/_index.scss b/src/components/accessibility/_index.scss index 98294afdf558..b8b7ffe9a8f1 100644 --- a/src/components/accessibility/_index.scss +++ b/src/components/accessibility/_index.scss @@ -1 +1,2 @@ @import 'screen_reader'; +@import 'skip_link'; diff --git a/src/components/accessibility/_skip_link.scss b/src/components/accessibility/_skip_link.scss new file mode 100644 index 000000000000..2dc6c46c9101 --- /dev/null +++ b/src/components/accessibility/_skip_link.scss @@ -0,0 +1,18 @@ +.euiSkipLink { + @include euiSlightShadow; + display: block; + z-index: $euiZHeader + 1; + background-color: $euiColorPrimary; + color: $euiColorGhost; + font-size: $euiFontSizeS; + padding: $euiSizeM $euiSize; + + &:focus, + &:hover { + position: fixed; + top: 0; + left: $euiSizeS; + border-radius: 0 0 $euiBorderRadius $euiBorderRadius; + text-decoration: underline; + } +} diff --git a/src/components/accessibility/index.ts b/src/components/accessibility/index.ts index d63ef5aa8008..06e7f202092d 100644 --- a/src/components/accessibility/index.ts +++ b/src/components/accessibility/index.ts @@ -1,2 +1,3 @@ export { EuiKeyboardAccessible } from './keyboard_accessible'; export { EuiScreenReaderOnly } from './screen_reader'; +export { EuiSkipLink } from './skip_link'; diff --git a/src/components/accessibility/skip_link.tsx b/src/components/accessibility/skip_link.tsx new file mode 100644 index 000000000000..27ddfbd86f31 --- /dev/null +++ b/src/components/accessibility/skip_link.tsx @@ -0,0 +1,34 @@ +import React, { FunctionComponent } from 'react'; +import classNames from 'classnames'; +import { EuiScreenReaderOnly } from '../accessibility/screen_reader'; + +export interface EuiSkipLinkProps { + /** + * Typically an anchor id (e.g. `#a11yMainContent`), the value provided here + * equates to the href for the link. + */ + destination: string; + + /** + * The text to be displayed as a link. + */ + label: string; + + tabIndex?: number; +} + +export const EuiSkipLink: FunctionComponent = ({ + destination, + label, + tabIndex = 0, +}) => { + const classes = classNames('euiSkipLink'); + + return ( + + + {label} + + + ); +}; diff --git a/src/components/index.js b/src/components/index.js index f4cb7cf66528..764036c894d5 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -4,7 +4,11 @@ export { EuiAspectRatio } from './aspect_ratio'; export { EuiAvatar } from './avatar'; -export { EuiKeyboardAccessible, EuiScreenReaderOnly } from './accessibility'; +export { + EuiKeyboardAccessible, + EuiScreenReaderOnly, + EuiSkipLink, +} from './accessibility'; export { EuiBadge, EuiBetaBadge, EuiNotificationBadge } from './badge';