From 3cde22cfd05627eff8051c925b90834c9cd3ec5a Mon Sep 17 00:00:00 2001 From: CJ Cenizal Date: Sun, 29 Apr 2018 20:54:06 -0700 Subject: [PATCH] Add role and aria attributes. --- .../__snapshots__/tabbed_content.test.js.snap | 90 +++++++++++++------ .../tabs/tabbed_content/tabbed_content.js | 36 ++++++-- .../tabbed_content/tabbed_content.test.js | 7 ++ 3 files changed, 102 insertions(+), 31 deletions(-) diff --git a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap index 669724555463..f6a460fe5198 100644 --- a/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap +++ b/src/components/tabs/tabbed_content/__snapshots__/tabbed_content.test.js.snap @@ -7,9 +7,10 @@ exports[`EuiTabbedContent behavior when selected tab state isn't controlled by t role="tablist" > -

- Elasticsearch content -

+
+

+ Elasticsearch content +

+
`; @@ -49,9 +57,10 @@ exports[`EuiTabbedContent is rendered 1`] = ` role="tablist" > -

- Elasticsearch content -

+
+

+ Elasticsearch content +

+
`; @@ -87,9 +103,10 @@ exports[`EuiTabbedContent props initialSelectedTab is rendered 1`] = ` role="tablist" > -

- Kibana content -

+
+

+ Kibana content +

+
`; @@ -125,9 +149,10 @@ exports[`EuiTabbedContent props selectedTab is rendered 1`] = ` role="tablist" > -

- Kibana content -

+
+

+ Kibana content +

+
`; @@ -163,9 +195,10 @@ exports[`EuiTabbedContent props size is rendered 1`] = ` role="tablist" > -

- Elasticsearch content -

+
+

+ Elasticsearch content +

+
`; diff --git a/src/components/tabs/tabbed_content/tabbed_content.js b/src/components/tabs/tabbed_content/tabbed_content.js index 71677dd82a83..de7e1c20f030 100644 --- a/src/components/tabs/tabbed_content/tabbed_content.js +++ b/src/components/tabs/tabbed_content/tabbed_content.js @@ -1,13 +1,18 @@ import React, { Component } from 'react' import PropTypes from 'prop-types'; +import { htmlIdGenerator } from '../../../services'; + import { EuiTabs, SIZES } from '../tabs'; import { EuiTab } from '../tab'; +const makeId = htmlIdGenerator(); + export class EuiTabbedContent extends Component { static propTypes = { className: PropTypes.string, - tabs: PropTypes.array.isRequired, + // We use the id to associate tabs with panels for accessibility. + tabs: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.string.isRequired })).isRequired, onTabClick: PropTypes.func, selectedTab: PropTypes.object, initialSelectedTab: PropTypes.object, @@ -19,6 +24,8 @@ export class EuiTabbedContent extends Component { const { initialSelectedTab, selectedTab, tabs } = props; + this.rootId = makeId(); + this.state = { selectedTab: selectedTab || initialSelectedTab || tabs[0], }; @@ -47,19 +54,30 @@ export class EuiTabbedContent extends Component { // Allow the consumer to control tab selection. const selectedTab = externalSelectedTab || this.state.selectedTab - const { content } = selectedTab + + const { + content: selectedTabContent, + id: selectedTabId, + } = selectedTab return (
{ - tabs.map((tab, index) => { - const { id, name, ...tabProps } = tab + tabs.map((tab) => { + const { + id, + name, + content, // eslint-disable-line no-unused-vars + ...tabProps + } = tab const props = { - key: id !== undefined ? id : index, + key: id, + id, ...tabProps, onClick: () => this.onTabClick(tab), isSelected: tab === selectedTab, + 'aria-controls': `${this.rootId}-${id}`, }; return {name}; @@ -67,7 +85,13 @@ export class EuiTabbedContent extends Component { } - {content} +
+ {selectedTabContent} +
) } diff --git a/src/components/tabs/tabbed_content/tabbed_content.test.js b/src/components/tabs/tabbed_content/tabbed_content.test.js index cba61a6dda22..8e9d70228b16 100644 --- a/src/components/tabs/tabbed_content/tabbed_content.test.js +++ b/src/components/tabs/tabbed_content/tabbed_content.test.js @@ -5,12 +5,19 @@ import { requiredProps, findTestSubject } from '../../../test'; import { EuiTabbedContent } from './tabbed_content'; +// Mock the htmlIdGenerator to generate predictable ids for snapshot tests +jest.mock('../../../services/accessibility/html_id_generator', () => ({ + htmlIdGenerator: () => { return () => 42; }, +})); + const elasticsearchTab = { + id: 'es', title: `Elasticsearch`, content:

Elasticsearch content

, }; const kibanaTab = { + id: 'kibana', title: `Kibana`, 'data-test-subj': 'kibanaTab', content:

Kibana content

,