fix(tabs): make tab panels focusable (#2281)
This commit is contained in:
parent
3829e2dce5
commit
08a1cb1688
3 changed files with 64 additions and 38 deletions
5
.changeset/ninety-needles-drop.md
Normal file
5
.changeset/ninety-needles-drop.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@lion/ui': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
[tabs] make tab panels focusable
|
||||||
|
|
@ -19,6 +19,16 @@ function setupPanel({ el, uid }) {
|
||||||
el.setAttribute('id', `panel-${uid}`);
|
el.setAttribute('id', `panel-${uid}`);
|
||||||
el.setAttribute('role', 'tabpanel');
|
el.setAttribute('role', 'tabpanel');
|
||||||
el.setAttribute('aria-labelledby', `button-${uid}`);
|
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');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -452,25 +452,7 @@ describe('<lion-tabs>', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Accessibility', () => {
|
describe('Accessibility', () => {
|
||||||
it('does not make panels focusable', async () => {
|
describe('Tabs', () => {
|
||||||
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 () => {
|
it('makes selected tab focusable (other tabs are unfocusable)', async () => {
|
||||||
const el = /** @type {LionTabs} */ (
|
const el = /** @type {LionTabs} */ (
|
||||||
await fixture(html`
|
await fixture(html`
|
||||||
|
|
@ -490,7 +472,6 @@ describe('<lion-tabs>', () => {
|
||||||
expect(tabs[2]).to.have.attribute('tabindex', '-1');
|
expect(tabs[2]).to.have.attribute('tabindex', '-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Tabs', () => {
|
|
||||||
it('links ids of content items to tab via [aria-controls]', async () => {
|
it('links ids of content items to tab via [aria-controls]', async () => {
|
||||||
const el = /** @type {LionTabs} */ (
|
const el = /** @type {LionTabs} */ (
|
||||||
await fixture(html`
|
await fixture(html`
|
||||||
|
|
@ -562,6 +543,36 @@ describe('<lion-tabs>', () => {
|
||||||
expect(panels[0]).to.have.attribute('aria-labelledby', tabs[0].id);
|
expect(panels[0]).to.have.attribute('aria-labelledby', tabs[0].id);
|
||||||
expect(panels[1]).to.have.attribute('aria-labelledby', tabs[1].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');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue