From 39ba09e1eb29f44613c7551cf82668ed0b7d117b Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Wed, 1 Sep 2021 20:40:45 -0700 Subject: [PATCH 1/8] Update .euiScreenReaderOnly to use clip - this prevents issues with absolute positioning and scrolling containers, and works on all modern browsers supported by EUI --- src/global_styling/mixins/_helpers.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/global_styling/mixins/_helpers.scss b/src/global_styling/mixins/_helpers.scss index 9527f83f1428..c2bdac6b580e 100644 --- a/src/global_styling/mixins/_helpers.scss +++ b/src/global_styling/mixins/_helpers.scss @@ -110,6 +110,8 @@ position: absolute; left: -10000px; top: auto; + clip: rect(0 0 0 0); + clip-path: inset(50%); width: 1px; height: 1px; overflow: hidden; From fd6961229afa5ff26e606ece10510f5f3d574de8 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Thu, 2 Sep 2021 10:55:54 -0700 Subject: [PATCH 2/8] [PR feedback] Add comment with more context --- src/global_styling/mixins/_helpers.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/global_styling/mixins/_helpers.scss b/src/global_styling/mixins/_helpers.scss index c2bdac6b580e..6cf16499b54b 100644 --- a/src/global_styling/mixins/_helpers.scss +++ b/src/global_styling/mixins/_helpers.scss @@ -106,6 +106,9 @@ } // Hiding elements offscreen to only be read by screen reader +// NOTE: Hidden absolute positioning can cause issues with scrolling/overflow. +// `clip` and `left` (for Chromium browsers) are needed to prevent these issues - +// @see https://github.com/elastic/eui/pull/5130 for more info @mixin euiScreenReaderOnly { position: absolute; left: -10000px; From f27dc38993c8252dd1414daaf88d29ff8f88db63 Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 7 Sep 2021 09:18:14 -0700 Subject: [PATCH 3/8] Fix screenReaderOnly CSS to only apply to check/radio inputs with labels --- src/components/form/checkbox/_checkbox.scss | 4 +++- src/components/form/radio/_radio.scss | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/form/checkbox/_checkbox.scss b/src/components/form/checkbox/_checkbox.scss index 3396683b6f23..23d47cee76fe 100644 --- a/src/components/form/checkbox/_checkbox.scss +++ b/src/components/form/checkbox/_checkbox.scss @@ -1,9 +1,11 @@ .euiCheckbox { position: relative; - .euiCheckbox__input { + &:not(.euiCheckbox--noLabel) .euiCheckbox__input { @include euiScreenReaderOnly; + } + .euiCheckbox__input { ~ .euiCheckbox__label { display: inline-block; padding-left: ($euiCheckBoxSize * 1.5); diff --git a/src/components/form/radio/_radio.scss b/src/components/form/radio/_radio.scss index 9fb5685d59ca..bff51dc3841d 100644 --- a/src/components/form/radio/_radio.scss +++ b/src/components/form/radio/_radio.scss @@ -1,9 +1,11 @@ .euiRadio { position: relative; - .euiRadio__input { + &:not(.euiRadio--noLabel) .euiRadio__input { @include euiScreenReaderOnly; + } + .euiRadio__input { ~ .euiRadio__label { display: inline-block; padding-left: ($euiRadioSize * 1.5); From 967886ef4e7b569f395915204732d2535b4b2f0b Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 7 Sep 2021 09:24:38 -0700 Subject: [PATCH 4/8] Clean up noLabel input CSS that was overriding previous screen reader CSS --- src/components/form/checkbox/_checkbox.scss | 1 - src/components/form/radio/_radio.scss | 1 - 2 files changed, 2 deletions(-) diff --git a/src/components/form/checkbox/_checkbox.scss b/src/components/form/checkbox/_checkbox.scss index 23d47cee76fe..22d32c1e2e2e 100644 --- a/src/components/form/checkbox/_checkbox.scss +++ b/src/components/form/checkbox/_checkbox.scss @@ -92,7 +92,6 @@ opacity: 0; /* 1 */ z-index: 1; /* 1 */ margin: 0; /* 1 */ - left: 0; /* 1 */ cursor: pointer; } } diff --git a/src/components/form/radio/_radio.scss b/src/components/form/radio/_radio.scss index bff51dc3841d..196cde246021 100644 --- a/src/components/form/radio/_radio.scss +++ b/src/components/form/radio/_radio.scss @@ -80,7 +80,6 @@ opacity: 0; /* 1 */ z-index: 1; /* 1 */ margin: 0; /* 1 */ - left: 0; /* 1 */ cursor: pointer; } } From e26b2e4dc3143cba4f2453e3b9299c343bacca9e Mon Sep 17 00:00:00 2001 From: Constance Chen Date: Tue, 7 Sep 2021 11:02:09 -0700 Subject: [PATCH 5/8] Add changelog entry --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a7cb56a6bf7..2663b4a657cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## [`master`](https://github.com/elastic/eui/tree/master) -No public interface changes since `37.6.2`. +**Breaking changes** + +- Added `clip` property to `EuiScreenReaderOnly`, to fix positioning issues within scrolling containers ([#5152](https://github.com/elastic/eui/pull/5152)) ## [`37.6.2`](https://github.com/elastic/eui/tree/v37.6.2) From 5833109a7129f65185ecb7cc238e4320da51d9d5 Mon Sep 17 00:00:00 2001 From: Caroline Horn <549577+cchaos@users.noreply.github.com> Date: Fri, 10 Sep 2021 13:45:49 -0400 Subject: [PATCH 6/8] [PR feedback] Docs & Comments & Updates styles for EuiScreenReaderOnly https://github.com/constancecchen/eui/pull/2 * [Docs] Updated Accessiblity Utility pages with more nuances about EuiScreenReaderOnly * Remove `euiScreenReaderOnly` mixin from checkbox and radio styles in favor of always having the input * Commented Sass * [EuiLink] Position relative if `target=_blank` for positioning screen reader text --- .../accessibility/accessibility_example.js | 148 +++++++++++++----- .../src/views/accessibility/screen_reader.tsx | 53 ++----- .../accessibility/screen_reader_button.tsx | 33 ++++ .../accessibility/screen_reader_focus.tsx | 18 +++ .../{skip_link.js => skip_link.tsx} | 20 --- src/components/form/checkbox/_checkbox.scss | 37 +++-- src/components/form/radio/_radio.scss | 36 ++--- src/components/link/_link.scss | 5 + src/global_styling/mixins/_helpers.scss | 18 ++- 9 files changed, 220 insertions(+), 148 deletions(-) create mode 100644 src-docs/src/views/accessibility/screen_reader_button.tsx create mode 100644 src-docs/src/views/accessibility/screen_reader_focus.tsx rename src-docs/src/views/accessibility/{skip_link.js => skip_link.tsx} (64%) diff --git a/src-docs/src/views/accessibility/accessibility_example.js b/src-docs/src/views/accessibility/accessibility_example.js index cf9ae2c06fd7..c123711dbfdf 100644 --- a/src-docs/src/views/accessibility/accessibility_example.js +++ b/src-docs/src/views/accessibility/accessibility_example.js @@ -1,7 +1,5 @@ import React from 'react'; -import { renderToHtml } from '../../services'; - import { GuideSectionTypes } from '../../components'; import { @@ -10,32 +8,25 @@ import { EuiLink, EuiSkipLink, EuiScreenReaderOnly, + EuiSpacer, } from '../../../../src/components'; import ScreenReaderOnly from './screen_reader'; +import ScreenReaderFocus from './screen_reader_focus'; +import ScreenReaderButton from './screen_reader_button'; import SkipLink from './skip_link'; -const screenReaderOnlyHtml = renderToHtml(ScreenReaderOnly); const screenReaderOnlySource = require('!!raw-loader!./screen_reader'); -const screenReaderOnlySnippet = [ - ` - - -`, - ` - - -`, -]; +const screenReaderFocusSource = require('!!raw-loader!./screen_reader_focus'); +const screenReaderButtonSource = require('!!raw-loader!./screen_reader_button'); -const skipLinkHtml = renderToHtml(SkipLink); const skipLinkSource = require('!!raw-loader!./skip_link'); const skipLinkSnippet = [ - ` + ` Skip to content `, - ` + ` Skip to main content `, @@ -51,19 +42,15 @@ export const AccessibilityExample = { type: GuideSectionTypes.JS, code: screenReaderOnlySource, }, - { - type: GuideSectionTypes.HTML, - code: screenReaderOnlyHtml, - }, ], text: ( -
+ <>

- Use the EuiScreenReaderOnly component to visually - hide elements while still allowing them to be read by screen - readers. In certain cases, you may want to use the{' '} - showOnFocus prop to display screen reader-only - content when in focus. + Using EuiScreenReaderOnly hides the wrapped element + from the page, but keeps it accessible for screen readers to provide + more context. It should be used primarily to mask{' '} + text and requires the child to be a single React + element for cloning.

+ Learn more about invisible content

-
+ +

+ + Using a screen reader, verify that there is a second paragraph. + +

+ ), props: { EuiScreenReaderOnly, }, - snippet: screenReaderOnlySnippet, + snippet: ` + +`, demo: , }, { - title: 'Skip link', source: [ { type: GuideSectionTypes.JS, - code: skipLinkSource, + code: screenReaderButtonSource, + }, + ], + text: ( + <> +

Within a button

+

+ If the screen reader content is contained within a + focusable element, you should consider adding{' '} + {'position: relative;'} to the + focusable element. This will fix any screen reader focus rings to + stay within the bounds of the focusable element. +

+

+ + Using a screen reader, tab through the following example with your + keyboard to verify the focus outline and screen reader text. + +

+ + ), + props: { + EuiScreenReaderOnly, + }, + snippet: ``, + demo: , + }, + { + source: [ + { + type: GuideSectionTypes.JS, + code: screenReaderFocusSource, }, + ], + text: ( + <> +

Showing on focus

+

+ If the wrapped element is focusable, you must use + the showOnFocus prop to visibly show the element + to all users when focused. +

+

+ + Tab through the following example with your keyboard to verify the + element is visible on focus. + +

+ + ), + props: { + EuiScreenReaderOnly, + }, + snippet: ` + +`, + demo: , + }, + { + title: 'Skip link', + source: [ { - type: GuideSectionTypes.HTML, - code: skipLinkHtml, + type: GuideSectionTypes.JS, + code: skipLinkSource, }, ], text: ( -

- The EuiSkipLink component allows users to bypass - navigation, or ornamental elements, and quickly reach the main content - of the page. -

+ <> +

+ The EuiSkipLink component allows users to bypass + navigation, or ornamental elements, and quickly reach the main + content of the page. It requires a destinationId{' '} + which should match the id of your main content. + You can also change the position to{' '} + fixed. +

+

+ + Tab through the following section to verify the{' '} + Skip to content button is visible on focus. + +

+ ), props: { EuiSkipLink }, snippet: skipLinkSnippet, diff --git a/src-docs/src/views/accessibility/screen_reader.tsx b/src-docs/src/views/accessibility/screen_reader.tsx index 7b8dcae0fb53..124823e11d16 100644 --- a/src-docs/src/views/accessibility/screen_reader.tsx +++ b/src-docs/src/views/accessibility/screen_reader.tsx @@ -1,51 +1,16 @@ import React from 'react'; -import { EuiScreenReaderOnly } from '../../../../src/components/accessibility/screen_reader'; -import { EuiCallOut } from '../../../../src/components/call_out'; -import { EuiText } from '../../../../src/components/text'; -import { EuiTitle } from '../../../../src/components/title'; -import { EuiLink } from '../../../../src/components/link'; +import { EuiScreenReaderOnly, EuiText } from '../../../../src/components'; export default () => ( -
- - -

Visually hide content

-
+ +

This is the first paragraph. It is visible to all.

+

- - Use a screenreader to verify that there is a second paragraph in this - example: - + This is the second paragraph. It is hidden for sighted users but visible + to screen readers.

-

This is the first paragraph. It is visible to all.

- -

- This is the second paragraph. It is hidden for sighted users but - visible to screen readers. -

-
-

This is the third paragraph. It is visible to all.

- -

Show on focus

-
-

- - Tab through this section with your keyboard to display a ‘Skip - navigation’ link: - -

-

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

- -
-
+ +

This is the third paragraph. It is visible to all.

+ ); diff --git a/src-docs/src/views/accessibility/screen_reader_button.tsx b/src-docs/src/views/accessibility/screen_reader_button.tsx new file mode 100644 index 000000000000..a12511776d1a --- /dev/null +++ b/src-docs/src/views/accessibility/screen_reader_button.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import { + EuiScreenReaderOnly, + EuiText, + EuiLink, +} from '../../../../src/components'; + +export default () => ( + +

+ Without relative position:{' '} + + Link text{' '} + + has screen reader text + + +

+

+ With releative position:{' '} + + Link text{' '} + + has screen reader text + + +

+
+); diff --git a/src-docs/src/views/accessibility/screen_reader_focus.tsx b/src-docs/src/views/accessibility/screen_reader_focus.tsx new file mode 100644 index 000000000000..b145df42fea4 --- /dev/null +++ b/src-docs/src/views/accessibility/screen_reader_focus.tsx @@ -0,0 +1,18 @@ +import React from 'react'; + +import { + EuiScreenReaderOnly, + EuiText, + EuiLink, +} from '../../../../src/components'; + +export default () => ( + +

+ This link is visible to all on focus:{' '} + + Link text + +

+
+); diff --git a/src-docs/src/views/accessibility/skip_link.js b/src-docs/src/views/accessibility/skip_link.tsx similarity index 64% rename from src-docs/src/views/accessibility/skip_link.js rename to src-docs/src/views/accessibility/skip_link.tsx index 1499f5a2169a..44bce0567b8f 100644 --- a/src-docs/src/views/accessibility/skip_link.js +++ b/src-docs/src/views/accessibility/skip_link.tsx @@ -3,7 +3,6 @@ import React, { useState } from 'react'; import { EuiSkipLink, EuiCallOut, - EuiText, EuiSpacer, EuiSwitch, } from '../../../../src/components'; @@ -13,25 +12,6 @@ export default () => { return ( <> - - {isFixed ? ( -

- - Tab through this section and a fixed{' '} - Skip to main content link will appear atop this - page. - -

- ) : ( -

- - Tab through this section and a Skip to content{' '} - link will appear below. - -

- )} -
-