fix(tabs): make tab panels focusable (#2281)

This commit is contained in:
gerjanvangeest 2024-05-22 09:24:20 +02:00 committed by GitHub
parent 3829e2dce5
commit 08a1cb1688
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 38 deletions

View file

@ -0,0 +1,5 @@
---
'@lion/ui': patch
---
[tabs] make tab panels focusable

View file

@ -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');
}
}
/**

View file

@ -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`
@ -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');
});
});
});