diff --git a/CHANGELOG.md b/CHANGELOG.md index 777c40c70cc..5a82de0a27b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ **Bug fixes** - Fixed building dev & docs on Windows ([#2847](https://github.com/elastic/eui/pull/2847)) +- Fixed screen reader discovery issues with `EuiBottomBar` and `EuiControlBar` ([#2861](https://github.com/elastic/eui/pull/2861)) - Fixed a bug in `EuiDataGrid` causing the first cell to autofocus if interactive ([#2872](https://github.com/elastic/eui/pull/2872)) **Breaking changes** diff --git a/src/components/bottom_bar/__snapshots__/bottom_bar.test.tsx.snap b/src/components/bottom_bar/__snapshots__/bottom_bar.test.tsx.snap index 2cc54e4350b..8ec6d9cb6ee 100644 --- a/src/components/bottom_bar/__snapshots__/bottom_bar.test.tsx.snap +++ b/src/components/bottom_bar/__snapshots__/bottom_bar.test.tsx.snap @@ -2,74 +2,107 @@ exports[`EuiBottomBar is rendered 1`] = ` Array [ -

- There is a new menu opening with page level controls at the end of the document. -

, -
+

+ Page level controls +

Content -
, + , +

+ There is a new region landmark with page level controls at the end of the document. +

, ] `; exports[`EuiBottomBar props paddingSize l is rendered 1`] = ` Array [ +
+

+ Page level controls +

+
,

- There is a new menu opening with page level controls at the end of the document. + There is a new region landmark with page level controls at the end of the document.

, -
, ] `; exports[`EuiBottomBar props paddingSize m is rendered 1`] = ` Array [ +
+

+ Page level controls +

+
,

- There is a new menu opening with page level controls at the end of the document. + There is a new region landmark with page level controls at the end of the document.

, -
, ] `; exports[`EuiBottomBar props paddingSize none is rendered 1`] = ` Array [ +
+

+ Page level controls +

+
,

- There is a new menu opening with page level controls at the end of the document. + There is a new region landmark with page level controls at the end of the document.

, -
, ] `; exports[`EuiBottomBar props paddingSize s is rendered 1`] = ` Array [ +
+

+ Page level controls +

+
,

- There is a new menu opening with page level controls at the end of the document. + There is a new region landmark with page level controls at the end of the document.

, -
, ] `; diff --git a/src/components/bottom_bar/bottom_bar.tsx b/src/components/bottom_bar/bottom_bar.tsx index 67d633ac67b..e8e5ecfdd31 100644 --- a/src/components/bottom_bar/bottom_bar.tsx +++ b/src/components/bottom_bar/bottom_bar.tsx @@ -1,10 +1,9 @@ -import React, { Component } from 'react'; import classNames from 'classnames'; - -import { CommonProps } from '../common'; -import { EuiPortal } from '../portal'; +import React, { Component } from 'react'; import { EuiScreenReaderOnly } from '../accessibility'; +import { CommonProps } from '../common'; import { EuiI18n } from '../i18n'; +import { EuiPortal } from '../portal'; type BottomBarPaddingSize = 'none' | 's' | 'm' | 'l'; @@ -28,10 +27,15 @@ interface Props extends CommonProps { * Padding applied to the bar */ paddingSize?: BottomBarPaddingSize; + + /** + * Customize the screen reader heading that helps users find this control. Default is "Page level controls". + */ + landmarkHeading?: string; } export class EuiBottomBar extends Component { - private bar: HTMLDivElement | null = null; + private bar: HTMLElement | null = null; componentDidMount() { const height = this.bar ? this.bar.clientHeight : -1; @@ -42,7 +46,7 @@ export class EuiBottomBar extends Component { } componentWillUnmount() { - document.body.style.paddingBottom = null; + document.body.style.paddingBottom = ''; if (this.props.bodyClassName) { document.body.classList.remove(this.props.bodyClassName); } @@ -54,6 +58,7 @@ export class EuiBottomBar extends Component { className, paddingSize = 'm', bodyClassName, + landmarkHeading, ...rest } = this.props; @@ -65,22 +70,46 @@ export class EuiBottomBar extends Component { return ( + + {(screenReaderHeading: string) => ( + // Though it would be better to use aria-labelledby than aria-label and not repeat the same string twice + // A bug in voiceover won't list some landmarks in the rotor without an aria-label +
{ + this.bar = node; + }} + {...rest}> + +

+ {landmarkHeading ? landmarkHeading : screenReaderHeading} +

+
+ {children} +
+ )} +

- + {landmarkHeading ? ( + + ) : ( + + )}

-
{ - this.bar = node; - }} - {...rest}> - {children} -
); } diff --git a/src/components/control_bar/__snapshots__/control_bar.test.tsx.snap b/src/components/control_bar/__snapshots__/control_bar.test.tsx.snap index 10317da2af9..bc1c95d46f6 100644 --- a/src/components/control_bar/__snapshots__/control_bar.test.tsx.snap +++ b/src/components/control_bar/__snapshots__/control_bar.test.tsx.snap @@ -1,12 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`EuiControlBar is rendered 1`] = ` -
+

+ Page level controls +

@@ -70,7 +75,7 @@ exports[`EuiControlBar is rendered 1`] = ` Flight 815
-
+ `; exports[`EuiControlBar props leftOffset is rendered 1`] = ` @@ -134,10 +139,16 @@ exports[`EuiControlBar props leftOffset is rendered 1`] = ` -
+

+ Page level controls +

@@ -201,134 +212,166 @@ exports[`EuiControlBar props leftOffset is rendered 1`] = ` Flight 815
-
+ +

+ There is a new region landmark with page level controls at the end of the document. +

} > -
-
- + +

+ Page level controls +

+
+
- - - - + + + +
+ + + + components + + + + + - - Sound the Alarm + + Sound the Alarm + - - - -
- Close the Hatch -
-
- + + +
+ Close the Hatch +
+ +
+ +
- -
- +
+ + + +

+ - Flight 815 - -

-
+ There is a new region landmark with page level controls at the end of the document. + +

+ @@ -396,10 +439,16 @@ exports[`EuiControlBar props maxHeight is rendered 1`] = ` -
+

+ Page level controls +

@@ -463,134 +512,166 @@ exports[`EuiControlBar props maxHeight is rendered 1`] = ` Flight 815
-
+ +

+ There is a new region landmark with page level controls at the end of the document. +

} > -
-
- + +

+ Page level controls +

+
+
- - - - + + + +
+ + + + components + + + + + - - Sound the Alarm + + Sound the Alarm + - - - -
- Close the Hatch -
-
- + + +
+ Close the Hatch +
+ +
+ +
- -
- +
+ + + +

+ - Flight 815 - -

-
+ There is a new region landmark with page level controls at the end of the document. + +

+ @@ -657,10 +738,16 @@ exports[`EuiControlBar props mobile is rendered 1`] = ` -
+

+ Page level controls +

@@ -724,134 +811,166 @@ exports[`EuiControlBar props mobile is rendered 1`] = ` Flight 815
-
+ +

+ There is a new region landmark with page level controls at the end of the document. +

} > -
-
- + +

+ Page level controls +

+
+
- - - - + + + +
+ + + + components + + + + + - - Sound the Alarm + + Sound the Alarm + - - - -
- Close the Hatch -
-
- + + +
+ Close the Hatch +
+ +
+ +
- -
- +
+ + + +

+ - Flight 815 - -

-
+ There is a new region landmark with page level controls at the end of the document. + +

+ @@ -914,130 +1033,143 @@ exports[`EuiControlBar props position is rendered 1`] = ` showOnMobile={false} size="l" > -
-
- + +

+ Page level controls +

+
+
- - - - + + + +
+ + + + components + + + + + - - Sound the Alarm + + Sound the Alarm + - - - -
- Close the Hatch -
-
- + +
+ Close the Hatch +
+
+ +
+ +
- -
- -
-
+ +
+ + `; @@ -1102,10 +1234,16 @@ exports[`EuiControlBar props rightOffset is rendered 1`] = ` -
+

+ Page level controls +

@@ -1169,134 +1307,166 @@ exports[`EuiControlBar props rightOffset is rendered 1`] = ` Flight 815
-
+ +

+ There is a new region landmark with page level controls at the end of the document. +

} > -
-
- + +

+ Page level controls +

+
+
- - - - + + + +
+ + + + components + + + + + - - Sound the Alarm + + Sound the Alarm + - - - -
- Close the Hatch -
-
- + +
+ Close the Hatch +
+
+ +
+ +
- -
- +
+ + + +

+ - Flight 815 - -

-
+ There is a new region landmark with page level controls at the end of the document. + +

+ @@ -1363,10 +1533,16 @@ exports[`EuiControlBar props showContent is rendered 1`] = ` -
+

+ Page level controls +

@@ -1435,139 +1611,171 @@ exports[`EuiControlBar props showContent is rendered 1`] = ` > Content
-
+ +

+ There is a new region landmark with page level controls at the end of the document. +

} > -
-
- + +

+ Page level controls +

+
+
- - - - + + + +
+ + + + components + + + + + - - Sound the Alarm + + Sound the Alarm + - - - -
- Close the Hatch -
-
- + +
+ Close the Hatch +
+
+ +
+ +
- + +
- -
-
+ + + +

- Content -

-
+ + There is a new region landmark with page level controls at the end of the document. + +

+ @@ -1634,10 +1842,16 @@ exports[`EuiControlBar props size is rendered 1`] = ` -
+

+ Page level controls +

@@ -1701,134 +1915,166 @@ exports[`EuiControlBar props size is rendered 1`] = ` Flight 815
-
+ +

+ There is a new region landmark with page level controls at the end of the document. +

} > -
-
- + +

+ Page level controls +

+
+
- - - - + + + +
+ + + + components + + + + + - - Sound the Alarm + + Sound the Alarm + - - - -
- Close the Hatch -
-
- + +
+ Close the Hatch +
+
+ +
+ +
- -
- +
+ + + +

+ - Flight 815 - -

-
+ There is a new region landmark with page level controls at the end of the document. + +

+ diff --git a/src/components/control_bar/control_bar.tsx b/src/components/control_bar/control_bar.tsx index 61c245c8805..139debaeed2 100644 --- a/src/components/control_bar/control_bar.tsx +++ b/src/components/control_bar/control_bar.tsx @@ -1,27 +1,28 @@ +import classNames from 'classnames'; import React, { + ButtonHTMLAttributes, Component, HTMLAttributes, - ButtonHTMLAttributes, Ref, } from 'react'; -import classNames from 'classnames'; -import { - CommonProps, - ExclusiveUnion, - PropsForAnchor, - PropsForButton, -} from '../common'; -// @ts-ignore-next-line +import { EuiScreenReaderOnly } from '../accessibility'; import { EuiBreadcrumbs, EuiBreadcrumbsProps } from '../breadcrumbs'; import { EuiButton, EuiButtonIcon, - EuiButtonProps, EuiButtonIconProps, + EuiButtonProps, } from '../button'; -import { EuiPortal } from '../portal'; +import { + CommonProps, + ExclusiveUnion, + PropsForAnchor, + PropsForButton, +} from '../common'; +import { EuiI18n } from '../i18n'; import { EuiIcon } from '../icon'; import { EuiIconProps } from '../icon/icon'; +import { EuiPortal } from '../portal'; /** * Extends EuiButton excluding `size`. Requires `label` as the `children`. @@ -190,6 +191,11 @@ export type EuiControlBarProps = HTMLAttributes & * Optional class applied to the body used when `position = fixed` */ bodyClassName?: string; + + /** + * Customize the screen reader heading that helps users find this control. Default is "Page level controls". + */ + landmarkHeading?: string; }; interface EuiControlBarState { @@ -208,7 +214,7 @@ export class EuiControlBar extends Component< showContent: false, showOnMobile: false, }; - private bar: HTMLDivElement | null = null; + private bar: HTMLElement | null = null; componentDidMount() { if (this.props.position === 'fixed') { @@ -221,7 +227,7 @@ export class EuiControlBar extends Component< } componentWillUnmount() { - document.body.style.paddingBottom = null; + document.body.style.paddingBottom = ''; if (this.props.bodyClassName) { document.body.classList.remove(this.props.bodyClassName); } @@ -245,6 +251,7 @@ export class EuiControlBar extends Component< style, position, bodyClassName, + landmarkHeading, ...rest } = this.props; @@ -396,24 +403,57 @@ export class EuiControlBar extends Component< }; const controlBar = ( -
-
{ - this.bar = node; - }}> - {controls.map((control, index) => { - return controlItem(control, index); - })} -
- {this.props.showContent ? ( -
{children}
- ) : null} -
+ + {(screenReaderHeading: string) => ( + // Though it would be better to use aria-labelledby than aria-label and not repeat the same string twice + // A bug in voiceover won't list some landmarks in the rotor without an aria-label +
+ +

{landmarkHeading ? landmarkHeading : screenReaderHeading}

+
+
{ + this.bar = node; + }}> + {controls.map((control, index) => { + return controlItem(control, index); + })} +
+ {this.props.showContent ? ( +
{children}
+ ) : null} +
+ )} +
); return position === 'fixed' ? ( - {controlBar} + + {controlBar} + +

+ {landmarkHeading ? ( + + ) : ( + + )} +

+
+
) : ( controlBar );