Skip to content

Commit

Permalink
fix(tabs): make tab panels focusable (#2281)
Browse files Browse the repository at this point in the history
  • Loading branch information
gerjanvangeest committed May 22, 2024
1 parent 3829e2d commit 08a1cb1
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/ninety-needles-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@lion/ui': patch
---

[tabs] make tab panels focusable
10 changes: 10 additions & 0 deletions packages/ui/components/tabs/src/LionTabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ function setupPanel({ el, uid }) {
el.setAttribute('id', `panel-${uid}`);
el.setAttribute('role', 'tabpanel');
el.setAttribute('aria-labelledby', `button-${uid}`);
/**
* Facilitates navigation to panel content for assistive technology users.
*
* Focusable tab panel elements are recommended if any panels in a set contain
* content where the first element in the panel is not focusable.
* https://www.w3.org/WAI/ARIA/apg/patterns/tabs/examples/tabs-automatic/
*/
if (!el.hasAttribute('tabindex')) {
el.setAttribute('tabindex', '0');
}
}

/**
Expand Down
87 changes: 49 additions & 38 deletions packages/ui/components/tabs/test/lion-tabs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -452,45 +452,26 @@ describe('<lion-tabs>', () => {
});

describe('Accessibility', () => {
it('does not make panels focusable', async () => {
const el = /** @type {LionTabs} */ (
await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
<div slot="panel">panel 1</div>
<button slot="tab">tab 2</button>
<div slot="panel">panel 2</div>
</lion-tabs>
`)
);
expect(Array.from(el.children).find(child => child.slot === 'panel')).to.not.have.attribute(
'tabindex',
);
expect(Array.from(el.children).find(child => child.slot === 'panel')).to.not.have.attribute(
'tabindex',
);
});

it('makes selected tab focusable (other tabs are unfocusable)', async () => {
const el = /** @type {LionTabs} */ (
await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
<div slot="panel">panel 1</div>
<button slot="tab">tab 2</button>
<div slot="panel">panel 2</div>
<button slot="tab">tab 3</button>
<div slot="panel">panel 3</div>
</lion-tabs>
`)
);
const tabs = el.querySelectorAll('[slot=tab]');
expect(tabs[0]).to.have.attribute('tabindex', '0');
expect(tabs[1]).to.have.attribute('tabindex', '-1');
expect(tabs[2]).to.have.attribute('tabindex', '-1');
});

describe('Tabs', () => {
it('makes selected tab focusable (other tabs are unfocusable)', async () => {
const el = /** @type {LionTabs} */ (
await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
<div slot="panel">panel 1</div>
<button slot="tab">tab 2</button>
<div slot="panel">panel 2</div>
<button slot="tab">tab 3</button>
<div slot="panel">panel 3</div>
</lion-tabs>
`)
);
const tabs = el.querySelectorAll('[slot=tab]');
expect(tabs[0]).to.have.attribute('tabindex', '0');
expect(tabs[1]).to.have.attribute('tabindex', '-1');
expect(tabs[2]).to.have.attribute('tabindex', '-1');
});

it('links ids of content items to tab via [aria-controls]', async () => {
const el = /** @type {LionTabs} */ (
await fixture(html`
Expand Down Expand Up @@ -562,6 +543,36 @@ describe('<lion-tabs>', () => {
expect(panels[0]).to.have.attribute('aria-labelledby', tabs[0].id);
expect(panels[1]).to.have.attribute('aria-labelledby', tabs[1].id);
});

it('makes panel focusable', async () => {
const el = /** @type {LionTabs} */ (
await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
<div slot="panel">panel 1</div>
<button slot="tab">tab 2</button>
<div slot="panel">panel 2</div>
</lion-tabs>
`)
);
const panels = el.querySelectorAll('[slot=panel]');
expect(panels[0]).to.have.attribute('tabindex', '0');
});

it('does not override the tabindex already set on the panel', async () => {
const el = /** @type {LionTabs} */ (
await fixture(html`
<lion-tabs>
<button slot="tab">tab 1</button>
<div slot="panel" tabindex="-1">panel 1</div>
<button slot="tab">tab 2</button>
<div slot="panel">panel 2</div>
</lion-tabs>
`)
);
const panels = el.querySelectorAll('[slot=panel]');
expect(panels[0]).to.have.attribute('tabindex', '-1');
});
});
});

Expand Down

0 comments on commit 08a1cb1

Please sign in to comment.