Leave controls disabled by a fieldset out of the Sheet focus trap
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (push) Successful in 1m28s
CI / ci (pull_request) Successful in 1m28s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 18:17:15 -04:00
co-authored by Claude Opus 5.5
parent 0fa9cfe611
commit ef3e7d0e45
2 changed files with 34 additions and 7 deletions
+25
View File
@@ -137,6 +137,31 @@ describe('Sheet', () => {
expect(last).toHaveFocus()
})
it('does not stop the Tab trap on a control disabled by its fieldset', () => {
render(
<Sheet aria-label="Quest log" open onClose={() => {}}>
<fieldset disabled>
<button type="button">Disabled first</button>
</fieldset>
<button type="button">Try it</button>
<button type="button">Pass</button>
<fieldset disabled>
<button type="button">Disabled last</button>
</fieldset>
</Sheet>,
)
const first = screen.getByRole('button', { name: 'Try it' })
const last = screen.getByRole('button', { name: 'Pass' })
expect(first).toHaveFocus()
last.focus()
fireEvent.keyDown(last, { key: 'Tab' })
expect(first).toHaveFocus()
fireEvent.keyDown(first, { key: 'Tab', shiftKey: true })
expect(last).toHaveFocus()
})
it('wraps Tab and Shift+Tab inside the sheet', () => {
render(<Harness />)
openSheet()
+9 -7
View File
@@ -15,17 +15,19 @@ export type SheetProps = SheetName & {
const focusableSelector = [
'a[href]',
'button:not([disabled])',
'input:not([disabled])',
'select:not([disabled])',
'textarea:not([disabled])',
'button',
'input',
'select',
'textarea',
'[tabindex]',
].join(',')
// Whether an element can take keyboard focus: a negative tabIndex, a hidden,
// aria-hidden or inert ancestor (or self), display: none on the way up to the
// panel, or visibility: hidden all rule it out.
// Whether an element can take keyboard focus: being disabled (by its own
// attribute or a disabled fieldset), a negative tabIndex, a hidden, aria-hidden
// or inert ancestor (or self), display: none on the way up to the panel, or
// visibility: hidden all rule it out.
function isKeyboardFocusable(element: HTMLElement, panel: HTMLElement): boolean {
if (element.matches(':disabled')) return false
if (element.tabIndex < 0) return false
if (element.closest('[hidden], [aria-hidden="true"], [inert]')) return false
if (getComputedStyle(element).visibility === 'hidden') return false