diff --git a/CHANGELOG.md b/CHANGELOG.md index fc2d11604cf..b09a811d91e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ **Bug fixes** - Fixed tick and level alignment in `Eui[Dual]Range` ([#5181](https://github.com/elastic/eui/pull/5181)) -- Fixed duplicate IDs on mobile/desktop select all checkboxes in `EuiBasicTable` ([#5237](https://github.com/elastic/eui/pull/5237)) +- Fixed multiple accessibility issues in `EuiBasicTable` and `EuiInMemoryTable` ([#5237](https://github.com/elastic/eui/pull/5237), [#5241](https://github.com/elastic/eui/pull/5241)) - Fixed missing i18n token in `EuiBasicTable`'s no items message ([#5242](https://github.com/elastic/eui/pull/5242)) **Breaking changes** diff --git a/scripts/a11y-testing.js b/scripts/a11y-testing.js index daaf22b469f..d770e901c61 100644 --- a/scripts/a11y-testing.js +++ b/scripts/a11y-testing.js @@ -6,8 +6,6 @@ const docsPages = async (root, page) => { const pagesToSkip = [ `${root}#/layout/page`, // Has duplicate `
` element `${root}#/layout/page-header`, // Has duplicate `
` element - `${root}#/tabular-content/tables`, - `${root}#/tabular-content/in-memory-tables`, `${root}#/display/aspect-ratio`, `${root}#/forms/combo-box`, `${root}#/forms/color-selection`, diff --git a/src-docs/src/views/tables/actions/actions.js b/src-docs/src/views/tables/actions/actions.js index 05f462e6a08..97fac6c3eb1 100644 --- a/src-docs/src/views/tables/actions/actions.js +++ b/src-docs/src/views/tables/actions/actions.js @@ -318,6 +318,7 @@ export const Table = () => { { /> { return ( , @@ -320,7 +322,8 @@ export default class extends Component { }, { id: 'actions', - label: '', + label: 'Actions', + isVisuallyHiddenLabel: true, alignment: RIGHT_ALIGNMENT, isActionsPopover: true, width: '32px', @@ -437,8 +440,10 @@ export default class extends Component { renderSelectAll = (mobile) => { return ( ); + } else if (column.isVisuallyHiddenLabel) { + headers.push( + + + {column.label} + + + ); } else { headers.push( ); @@ -741,6 +756,7 @@ export default class extends Component { { align: RIGHT_ALIGNMENT, width: '40px', isExpander: true, + name: ( + + Expand rows + + ), render: (item) => ( toggleDetails(item)} @@ -195,6 +201,7 @@ export const Table = () => { {deleteButton} { {deleteButton} { return ( { return ( setPagination({ pageIndex: index }) } diff --git a/src-docs/src/views/tables/in_memory/in_memory_custom_sorting.js b/src-docs/src/views/tables/in_memory/in_memory_custom_sorting.js index a87a97ead0c..ca60886af87 100644 --- a/src-docs/src/views/tables/in_memory/in_memory_custom_sorting.js +++ b/src-docs/src/views/tables/in_memory/in_memory_custom_sorting.js @@ -38,6 +38,7 @@ export const Table = () => { return ( { { return ( { { { responsive=false.

-

+

To make your table work responsively, please make sure you add the following additional props to the top level table component (EuiBasicTable or{' '} EuiInMemoryTable): -

+

  • isSelectable: if the table has a single column of @@ -63,16 +63,15 @@ export const section = { which may/may not be hidden in hover
-

+

The mobileOptions object can be passed to the{' '} EuiTableRowCell directly or with each column item provided to EuiBasicTable. -

+

{exampleItem} -

Note:

- You can also change basic table row cell props like{' '} - truncateText and textOnly for + Note: You can also change basic table row cell props + like truncateText and textOnly for mobile layouts, though you must also be passing a mobile specific render function.

diff --git a/src-docs/src/views/tables/paginated/paginated.js b/src-docs/src/views/tables/paginated/paginated.js index aaccb37a24f..663a8c88a64 100644 --- a/src-docs/src/views/tables/paginated/paginated.js +++ b/src-docs/src/views/tables/paginated/paginated.js @@ -148,6 +148,7 @@ export const Table = () => { /> { { - + > + + `; @@ -1676,7 +1675,7 @@ exports[`EuiBasicTable with initial selection 1`] = ` compressed={false} data-test-subj="checkboxSelectRow-1" disabled={false} - id="_selection_column_1-checkbox" + id="__table_generated-id_selection_column_1-checkbox" indeterminate={false} onChange={[Function]} title="Select this row" @@ -1691,7 +1690,7 @@ exports[`EuiBasicTable with initial selection 1`] = ` className="euiCheckbox__input" data-test-subj="checkboxSelectRow-1" disabled={false} - id="_selection_column_1-checkbox" + id="__table_generated-id_selection_column_1-checkbox" onChange={[Function]} title="Select this row" type="checkbox" @@ -1769,7 +1768,7 @@ exports[`EuiBasicTable with initial selection 1`] = ` compressed={false} data-test-subj="checkboxSelectRow-2" disabled={false} - id="_selection_column_2-checkbox" + id="__table_generated-id_selection_column_2-checkbox" indeterminate={false} onChange={[Function]} title="Select this row" @@ -1784,7 +1783,7 @@ exports[`EuiBasicTable with initial selection 1`] = ` className="euiCheckbox__input" data-test-subj="checkboxSelectRow-2" disabled={false} - id="_selection_column_2-checkbox" + id="__table_generated-id_selection_column_2-checkbox" onChange={[Function]} title="Select this row" type="checkbox" @@ -1862,7 +1861,7 @@ exports[`EuiBasicTable with initial selection 1`] = ` compressed={false} data-test-subj="checkboxSelectRow-3" disabled={false} - id="_selection_column_3-checkbox" + id="__table_generated-id_selection_column_3-checkbox" indeterminate={false} onChange={[Function]} title="Select this row" @@ -1877,7 +1876,7 @@ exports[`EuiBasicTable with initial selection 1`] = ` className="euiCheckbox__input" data-test-subj="checkboxSelectRow-3" disabled={false} - id="_selection_column_3-checkbox" + id="__table_generated-id_selection_column_3-checkbox" onChange={[Function]} title="Select this row" type="checkbox" @@ -2346,18 +2345,17 @@ exports[`EuiBasicTable with pagination - 2nd page 1`] = ` - + > + + `; @@ -2477,18 +2475,17 @@ exports[`EuiBasicTable with pagination 1`] = ` - + > + + `; @@ -2735,18 +2732,17 @@ exports[`EuiBasicTable with pagination and selection 1`] = ` - + > + + `; @@ -2866,19 +2862,17 @@ exports[`EuiBasicTable with pagination, hiding the per page options 1`] = ` - + > + + `; @@ -3065,18 +3059,17 @@ exports[`EuiBasicTable with pagination, selection and sorting 1`] = ` - + > + + `; @@ -3356,18 +3349,17 @@ exports[`EuiBasicTable with pagination, selection, sorting and a single record a - + > + + `; @@ -3554,18 +3546,17 @@ exports[`EuiBasicTable with pagination, selection, sorting and column dataType 1 - + > + + `; @@ -3752,18 +3743,17 @@ exports[`EuiBasicTable with pagination, selection, sorting and column renderer 1 - + > + + `; @@ -4061,18 +4051,17 @@ exports[`EuiBasicTable with pagination, selection, sorting and multiple record a - + > + + `; @@ -4259,18 +4248,17 @@ exports[`EuiBasicTable with pagination, selection, sorting, column renderer and - + > + + `; diff --git a/src/components/basic_table/__snapshots__/in_memory_table.test.tsx.snap b/src/components/basic_table/__snapshots__/in_memory_table.test.tsx.snap index 1dbfcfc7b44..5071811d5d9 100644 --- a/src/components/basic_table/__snapshots__/in_memory_table.test.tsx.snap +++ b/src/components/basic_table/__snapshots__/in_memory_table.test.tsx.snap @@ -307,93 +307,75 @@ exports[`EuiInMemoryTable behavior pagination 1`] = ` - -
- -
- - - +
+
+ + + - -
- - - : - 2 - - } - closePopover={[Function]} - display="inlineBlock" - hasArrow={true} - isOpen={false} - ownFocus={true} - panelPaddingSize="none" +
-
-
+ - - + + + +
-
-
-
-
- -
+
+
+ - - - -
- -
-
-
-
- + + +
+
+ + +
+ + +
@@ -1148,7 +1163,7 @@ exports[`EuiInMemoryTable with initial selection 1`] = ` compressed={false} data-test-subj="checkboxSelectRow-1" disabled={false} - id="_selection_column_1-checkbox" + id="__table_generated-id_selection_column_1-checkbox" indeterminate={false} onChange={[Function]} title="Select this row" @@ -1163,7 +1178,7 @@ exports[`EuiInMemoryTable with initial selection 1`] = ` className="euiCheckbox__input" data-test-subj="checkboxSelectRow-1" disabled={false} - id="_selection_column_1-checkbox" + id="__table_generated-id_selection_column_1-checkbox" onChange={[Function]} title="Select this row" type="checkbox" @@ -1241,7 +1256,7 @@ exports[`EuiInMemoryTable with initial selection 1`] = ` compressed={false} data-test-subj="checkboxSelectRow-2" disabled={false} - id="_selection_column_2-checkbox" + id="__table_generated-id_selection_column_2-checkbox" indeterminate={false} onChange={[Function]} title="Select this row" @@ -1256,7 +1271,7 @@ exports[`EuiInMemoryTable with initial selection 1`] = ` className="euiCheckbox__input" data-test-subj="checkboxSelectRow-2" disabled={false} - id="_selection_column_2-checkbox" + id="__table_generated-id_selection_column_2-checkbox" onChange={[Function]} title="Select this row" type="checkbox" @@ -1334,7 +1349,7 @@ exports[`EuiInMemoryTable with initial selection 1`] = ` compressed={false} data-test-subj="checkboxSelectRow-3" disabled={false} - id="_selection_column_3-checkbox" + id="__table_generated-id_selection_column_3-checkbox" indeterminate={false} onChange={[Function]} title="Select this row" @@ -1349,7 +1364,7 @@ exports[`EuiInMemoryTable with initial selection 1`] = ` className="euiCheckbox__input" data-test-subj="checkboxSelectRow-3" disabled={false} - id="_selection_column_3-checkbox" + id="__table_generated-id_selection_column_3-checkbox" onChange={[Function]} title="Select this row" type="checkbox" diff --git a/src/components/basic_table/__snapshots__/pagination_bar.test.tsx.snap b/src/components/basic_table/__snapshots__/pagination_bar.test.tsx.snap index 5e0c5eb64e9..af5dacb99df 100644 --- a/src/components/basic_table/__snapshots__/pagination_bar.test.tsx.snap +++ b/src/components/basic_table/__snapshots__/pagination_bar.test.tsx.snap @@ -7,6 +7,7 @@ exports[`PaginationBar render - custom page size options 1`] = ` /> extends Component< align={columnAlign} width={width} mobileOptions={mobileOptions} - data-test-subj={`tableHeaderCell_${name}_${index}`} + data-test-subj={`tableHeaderCell_${ + typeof name === 'string' ? name : '' + }_${index}`} description={description} {...sorting} > @@ -1168,7 +1164,7 @@ export class EuiBasicTable extends Component< {(selectThisRow: string) => ( extends Component< not configured. This callback must be implemented to handle pagination changes`); } - let ariaLabel: ReactElement | undefined = undefined; - - if (tableCaption) { - ariaLabel = ( - - ); - } - return ( - + + {(tablePagination: string) => ( + + )} + ); } } diff --git a/src/components/basic_table/pagination_bar.tsx b/src/components/basic_table/pagination_bar.tsx index ecf300ede29..f4695ed3c93 100644 --- a/src/components/basic_table/pagination_bar.tsx +++ b/src/components/basic_table/pagination_bar.tsx @@ -39,12 +39,13 @@ export interface Pagination { export interface PaginationBarProps { pagination: Pagination; + onPageSizeChange: ItemsPerPageChangeHandler; + onPageChange: PageChangeHandler; /** * id of the table being controlled */ 'aria-controls'?: string; - onPageSizeChange: ItemsPerPageChangeHandler; - onPageChange: PageChangeHandler; + 'aria-label'?: string; } export const defaults = { @@ -53,9 +54,10 @@ export const defaults = { export const PaginationBar = ({ pagination, - 'aria-controls': ariaControls, onPageSizeChange, onPageChange, + 'aria-controls': ariaControls, + 'aria-label': ariaLabel, }: PaginationBarProps) => { const pageSizeOptions = pagination.pageSizeOptions ? pagination.pageSizeOptions @@ -80,6 +82,7 @@ export const PaginationBar = ({ onChangeItemsPerPage={onPageSizeChange} onChangePage={onPageChange} aria-controls={ariaControls} + aria-label={ariaLabel} /> ); diff --git a/src/components/search_bar/filters/__snapshots__/field_value_selection_filter.test.tsx.snap b/src/components/search_bar/filters/__snapshots__/field_value_selection_filter.test.tsx.snap index 9040fa2f589..843b6ba9990 100644 --- a/src/components/search_bar/filters/__snapshots__/field_value_selection_filter.test.tsx.snap +++ b/src/components/search_bar/filters/__snapshots__/field_value_selection_filter.test.tsx.snap @@ -17,7 +17,6 @@ exports[`FieldValueSelectionFilter active - field is global 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -60,7 +59,6 @@ exports[`FieldValueSelectionFilter active - fields in options 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -103,7 +101,6 @@ exports[`FieldValueSelectionFilter inactive - field is global 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -159,7 +156,6 @@ exports[`FieldValueSelectionFilter inactive - fields in options 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -215,7 +211,6 @@ exports[`FieldValueSelectionFilter render - all configurations 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -258,7 +253,6 @@ exports[`FieldValueSelectionFilter render - fields in options 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -314,7 +308,6 @@ exports[`FieldValueSelectionFilter render - multi-select OR 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -357,7 +350,6 @@ exports[`FieldValueSelectionFilter render - options as a function 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" @@ -400,7 +392,6 @@ exports[`FieldValueSelectionFilter render - options as an array 1`] = ` closePopover={[Function]} display="inlineBlock" hasArrow={true} - id="field_value_selection_0" isOpen={false} ownFocus={true} panelClassName="euiFilterGroup__popoverPanel" diff --git a/src/components/search_bar/filters/field_value_selection_filter.tsx b/src/components/search_bar/filters/field_value_selection_filter.tsx index f4cdf94c5b4..2806889ef27 100644 --- a/src/components/search_bar/filters/field_value_selection_filter.tsx +++ b/src/components/search_bar/filters/field_value_selection_filter.tsx @@ -334,7 +334,7 @@ export class FieldValueSelectionFilter extends Component< } render() { - const { index, query, config } = this.props; + const { query, config } = this.props; const multiSelect = this.resolveMultiSelect(); const activeTop = this.isActiveField(config.field); @@ -368,7 +368,6 @@ export class FieldValueSelectionFilter extends Component< return ( = ({ isSorted, isSortAscending, className, - scope = 'col', + scope, mobileOptions = { show: true, }, @@ -155,6 +155,7 @@ export const EuiTableHeaderCell: FunctionComponent = ({ const styleObj = resolveWidthAsStyle(style, width); const CellComponent = children ? 'th' : 'td'; + const cellScope = CellComponent === 'th' ? scope ?? 'col' : undefined; // `scope` is only valid on `th` elements if (onSort || isSorted) { const buttonClasses = classNames('euiTableHeaderButton', { @@ -180,7 +181,7 @@ export const EuiTableHeaderCell: FunctionComponent = ({ return ( = ({ return (