Skip to content

Commit 776c719

Browse files
joshhanleycalebporzioclaude
authored
Update tabbable and focus-trap dependencies in focus plugin (#4737)
* Update `tabbable` and `focus-trap` dependencies in focus plugin Update `tabbable` from ^5.3.3 to ^6.4.0 and `focus-trap` from ^6.9.4 to ^8.0.0. These packages only support their most recently published version, so staying on older versions means no security patches. This addresses concerns raised in governmental security audits. Breaking changes in these packages (IE support dropped, displayCheck defaults) do not affect Alpine's usage patterns. * Add tests for radio buttons, inert attribute, and dynamic elements These tests cover scenarios related to the tabbable/focus-trap upgrade: - x-trap works with radio button groups - $focus.focusables excludes elements with inert attribute (new feature) - x-trap handles dynamically added focusable elements * Review fixes: restore lockfile name field to 'alpine' Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Caleb Porzio <calebporzio@gmail.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f5ee754 commit 776c719

File tree

3 files changed

+90
-24
lines changed

3 files changed

+90
-24
lines changed

package-lock.json

Lines changed: 24 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/focus/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"module": "dist/module.esm.js",
1515
"unpkg": "dist/cdn.min.js",
1616
"dependencies": {
17-
"focus-trap": "^6.9.4",
18-
"tabbable": "^5.3.3"
17+
"focus-trap": "^8.0.0",
18+
"tabbable": "^6.4.0"
1919
}
2020
}

tests/cypress/integration/plugins/focus.spec.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,67 @@ test('can disable x-trap autofocus with .noautofocus modifier',
397397
get('#2').should(haveFocus())
398398
}
399399
)
400+
401+
test('x-trap works with radio button groups',
402+
[html`
403+
<div x-data="{ open: false }">
404+
<input type="text" id="outside">
405+
<button id="open" @click="open = true">open</button>
406+
<div x-trap="open">
407+
<input type="radio" name="choice" id="radio1" value="1" checked>
408+
<input type="radio" name="choice" id="radio2" value="2">
409+
<input type="radio" name="choice" id="radio3" value="3">
410+
<button @click="open = false" id="close">close</button>
411+
</div>
412+
</div>
413+
`],
414+
({ get }) => {
415+
get('#outside').focus()
416+
get('#outside').should(haveFocus())
417+
get('#open').click()
418+
// Focus should be inside the trap (on the checked radio)
419+
get('#radio1').should(haveFocus())
420+
// Close and verify focus returns outside the trap
421+
get('#close').click()
422+
get('#open').should(haveFocus())
423+
},
424+
)
425+
426+
test('$focus.focusables excludes elements with inert attribute',
427+
[html`
428+
<div x-data>
429+
<h1 x-text="$focus.within($refs.container).focusables().length"></h1>
430+
<div x-ref="container">
431+
<button>1</button>
432+
<button inert>2</button>
433+
<button>3</button>
434+
</div>
435+
</div>
436+
`],
437+
({ get }) => {
438+
get('h1').should(haveText('2'))
439+
},
440+
)
441+
442+
test('x-trap handles dynamically added focusable elements',
443+
[html`
444+
<div x-data="{ open: false }">
445+
<button id="open" @click="open = true">open</button>
446+
<div x-trap="open" x-ref="trap">
447+
<button id="first">first</button>
448+
<button id="last" @click="$refs.trap.insertAdjacentHTML('beforeend', '<button id=dynamic>dynamic</button>')">add element</button>
449+
</div>
450+
</div>
451+
`],
452+
({ get }) => {
453+
get('#open').click()
454+
get('#first').should(haveFocus())
455+
cy.focused().tab()
456+
get('#last').should(haveFocus())
457+
get('#last').click()
458+
cy.focused().tab()
459+
get('#dynamic').should(haveFocus())
460+
cy.focused().tab()
461+
get('#first').should(haveFocus())
462+
},
463+
)

0 commit comments

Comments
 (0)