Skip to content

Commit 3de1564

Browse files
authored
Tabs - Implement aria-controls (#2637)
1 parent 1ef4f62 commit 3de1564

File tree

5 files changed

+23
-1
lines changed

5 files changed

+23
-1
lines changed

.changeset/short-rockets-press.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@hashicorp/design-system-components": patch
3+
---
4+
5+
`Tabs` - Implement `aria-controls` in tab for a11y improvements with toggled content

packages/components/src/components/hds/tabs/index.hbs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
didUpdateNode=this.didUpdateTab
2222
willDestroyNode=this.willDestroyTab
2323
tabIds=this._tabIds
24+
panelIds=this._panelIds
2425
selectedTabIndex=this.selectedTabIndex
2526
onClick=this.onClick
2627
onKeyUp=this.onKeyUp

packages/components/src/components/hds/tabs/tab.hbs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
role="tab"
1010
type="button"
1111
id={{this._tabId}}
12+
aria-controls={{this.coupledPanelId}}
1213
aria-selected={{if this.isSelected "true" "false"}}
1314
tabindex={{unless this.isSelected "-1"}}
1415
{{did-insert this.didInsertNode @isSelected}}

packages/components/src/components/hds/tabs/tab.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ import Component from '@glimmer/component';
77
import { guidFor } from '@ember/object/internals';
88
import { action } from '@ember/object';
99
import type { IconName } from '@hashicorp/flight-icons/svg';
10-
import type { HdsTabsTabIds } from './types';
10+
import type { HdsTabsTabIds, HdsTabsPanelIds } from './types';
1111

1212
export interface HdsTabsTabSignature {
1313
Args: {
1414
tabIds?: HdsTabsTabIds;
15+
panelIds?: HdsTabsPanelIds;
1516
selectedTabIndex?: number;
1617
icon?: IconName;
1718
count?: string;
@@ -52,6 +53,16 @@ export default class HdsTabsTab extends Component<HdsTabsTabSignature> {
5253
);
5354
}
5455

56+
/**
57+
* Get the ID of the panel coupled/associated with the tab (it's used by the `aria-controls` attribute)
58+
* @returns string}
59+
*/
60+
get coupledPanelId(): string | undefined {
61+
return this.nodeIndex !== undefined
62+
? this.args.panelIds?.[this.nodeIndex]
63+
: undefined;
64+
}
65+
5566
@action
5667
didInsertNode(element: HTMLButtonElement, positional: [boolean?]): void {
5768
const { didInsertNode } = this.args;

showcase/tests/integration/components/hds/tabs/index-test.js

+4
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ module('Integration | Component | hds/tabs/index', function (hooks) {
315315
assert
316316
.dom('[data-test="tab-1"] .hds-tabs__tab-button')
317317
.hasAttribute('role', 'tab');
318+
const panelId = find('[data-test="panel-1"]').getAttribute('id');
319+
assert
320+
.dom('[data-test="tab-1"] .hds-tabs__tab-button')
321+
.hasAttribute('aria-controls', panelId);
318322
assert.dom('[data-test="panel-1"]').hasAttribute('role', 'tabpanel');
319323
const tabId = find(
320324
'[data-test="tab-1"] .hds-tabs__tab-button'

0 commit comments

Comments
 (0)