Skip to content

Commit 7a8fa4a

Browse files
authored
Merge pull request #78 from github/fix-set-aria-selected
Fix set aria selected
2 parents 3a0377f + df9d585 commit 7a8fa4a

File tree

4 files changed

+88
-6
lines changed

4 files changed

+88
-6
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import '@github/tab-container-element'
3131
</tab-container>
3232
```
3333

34+
If none of the tabs have `aria-selected=true`, then the first tab will be selected automatically. You can also add the `default-tab=N` attribute to avoid having to set `aria-selected=true` on the desired tab.
35+
3436
### Events
3537

3638
- `tab-container-change` (bubbles, cancelable): fired on `<tab-container>` before a new tab is selected and visibility is updated. `event.tab` is the tab that will be focused and `tab.panel` is the panel that will be shown if the event isn't cancelled.

examples/index.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ <h2>Vertical (custom tablist)</h2>
8383
</div>
8484
</tab-container>
8585

86+
<h2>Set initially selected tab</h2>
87+
88+
<tab-container>
89+
<button type="button" id="tab-one" role="tab">Tab one</button>
90+
<button type="button" id="tab-two" role="tab" aria-selected="true">Tab two</button>
91+
<button type="button" id="tab-three" role="tab">Tab three</button>
92+
<div role="tabpanel" aria-labelledby="tab-one" hidden>
93+
Panel 1
94+
</div>
95+
<div role="tabpanel" aria-labelledby="tab-two">
96+
Panel 2
97+
</div>
98+
<div role="tabpanel" aria-labelledby="tab-three" hidden>
99+
Panel 3
100+
</div>
101+
</tab-container>
102+
86103
<h2>Panel with extra buttons</h2>
87104

88105
<tab-container>

src/tab-container-element.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,8 @@ export class TabContainerElement extends HTMLElement {
152152

153153
this.addEventListener('keydown', this)
154154
this.addEventListener('click', this)
155-
this.selectTab(
156-
Math.max(
157-
this.#tabs.findIndex(el => el.matches('[aria-selected=true]')),
158-
0,
159-
),
160-
)
155+
156+
this.selectTab(-1)
161157
this.#setupComplete = true
162158
}
163159

@@ -257,6 +253,9 @@ export class TabContainerElement extends HTMLElement {
257253
this.#beforeTabsSlot.assign(...beforeSlotted)
258254
this.#afterTabsSlot.assign(...afterTabSlotted)
259255
this.#afterPanelsSlot.assign(...afterSlotted)
256+
const defaultTab = Number(this.getAttribute('default-tab') || -1)
257+
const defaultIndex = defaultTab >= 0 ? defaultTab : this.#tabs.findIndex(el => el.matches('[aria-selected=true]'))
258+
index = index >= 0 ? index : Math.max(0, defaultIndex)
260259
}
261260

262261
const tabs = this.#tabs

test/test.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,70 @@ describe('tab-container', function () {
4545
})
4646
})
4747

48+
describe('after tree insertion with aria-selected on second tab', function () {
49+
beforeEach(function () {
50+
document.body.innerHTML = `
51+
<tab-container>
52+
<button type="button" role="tab">Tab one</button>
53+
<button type="button" role="tab" aria-selected="true">Tab two</button>
54+
<button type="button" role="tab">Tab three</button>
55+
<div role="tabpanel" hidden>
56+
Panel 1
57+
</div>
58+
<div role="tabpanel">
59+
Panel 2
60+
</div>
61+
<div role="tabpanel" hidden data-tab-container-no-tabstop>
62+
Panel 3
63+
</div>
64+
</tab-container>
65+
`
66+
tabs = Array.from(document.querySelectorAll('button'))
67+
panels = Array.from(document.querySelectorAll('[role="tabpanel"]'))
68+
})
69+
70+
afterEach(function () {
71+
document.body.innerHTML = ''
72+
})
73+
74+
it('the second tab is still selected', function () {
75+
assert.deepStrictEqual(tabs.map(isSelected), [false, true, false], 'Second tab is selected')
76+
assert.deepStrictEqual(panels.map(isHidden), [true, false, true], 'Second panel is visible')
77+
})
78+
})
79+
80+
describe('after tree insertion with default-tab', function () {
81+
beforeEach(function () {
82+
document.body.innerHTML = `
83+
<tab-container default-tab=1>
84+
<button type="button" role="tab">Tab one</button>
85+
<button type="button" role="tab">Tab two</button>
86+
<button type="button" role="tab">Tab three</button>
87+
<div role="tabpanel" hidden>
88+
Panel 1
89+
</div>
90+
<div role="tabpanel">
91+
Panel 2
92+
</div>
93+
<div role="tabpanel" hidden data-tab-container-no-tabstop>
94+
Panel 3
95+
</div>
96+
</tab-container>
97+
`
98+
tabs = Array.from(document.querySelectorAll('button'))
99+
panels = Array.from(document.querySelectorAll('[role="tabpanel"]'))
100+
})
101+
102+
afterEach(function () {
103+
document.body.innerHTML = ''
104+
})
105+
106+
it('the second tab is still selected', function () {
107+
assert.deepStrictEqual(tabs.map(isSelected), [false, true, false], 'Second tab is selected')
108+
assert.deepStrictEqual(panels.map(isHidden), [true, false, true], 'Second panel is visible')
109+
})
110+
})
111+
48112
describe('after tree insertion', function () {
49113
beforeEach(function () {
50114
document.body.innerHTML = `

0 commit comments

Comments
 (0)