Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/konnorrogers/focus-hunter
A focus trapping utility that respects shadow doms and slots
https://github.com/konnorrogers/focus-hunter
focus focustrap trap
Last synced: about 1 month ago
JSON representation
A focus trapping utility that respects shadow doms and slots
- Host: GitHub
- URL: https://github.com/konnorrogers/focus-hunter
- Owner: KonnorRogers
- License: mit
- Created: 2023-08-23T13:28:42.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-01-10T21:01:25.000Z (12 months ago)
- Last Synced: 2024-11-01T11:42:39.747Z (about 2 months ago)
- Topics: focus, focustrap, trap
- Language: JavaScript
- Homepage: https://konnorrogers.github.io/focus-hunter/
- Size: 10.4 MB
- Stars: 11
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
![Bundle Size Badge](https://deno.bundlejs.com/?q=focus-hunter&badge)
## Purpose
Focus trapping made easy for things like Dialogs.
## Why?
Because focus trapping sucks. But its a necessary evil.
## Demo
## Prior Art
- [Focus Trap](https://github.com/focus-trap/focus-trap) was attempted to be used, but was quite big (~5kb) and didn't handle multiple levels of shadow DOM. It is however a big inspiration for this library.
- This solution has been largely extracted from [Shoelace](https://shoelace.style)
## Differences from Focus Trap
Focus Hunter doesn't aim to do everything. It tries its best to keep a small minimal API and get out of your way.
This is reflected in bundle size.`focus-hunter` is `~1.5kb` minified + gzipped.
`focus-trap` is `~5.5kb` minified + gzipped.## Installation
```bash
npm install focus-hunter
```## Adding a trap
```js
// Create a trap
const trap = new Trap({ rootElement: document.querySelector("my-trap") })// Start the trap
trap.start()// Stop the trap
trap.stop()
```## All Options
```js
const trap = new Trap({
rootElement,
preventScroll, // Passed to `element.focus({ preventScroll })` for programmatically focused elements
})
```## Multiple Traps
Focus Trap is allowed to have multiple traps. It keeps track of the stacks using `window.focusHunter.trapStack` which
is implemented via a `Set`.There is also a stack of rootElements at `window.focusHunter.rootElementStack`
There 2 stacks are checked when you call `trap.start()` to ensure the rootElement isn't already being trapped and that
the trap isn't already active.```js
window.focusHunter.trapStack // => Set
window.focusHunter.rootElementStack // => Set
```## A note on iframes
While the focus trap can get to an `` it cannot find elements within a cross origin iframe
so they are excluded from the focus trap.## Differences from Shoelace
This library is largely me experimenting with generators. Beyond internal implementation details, here are some differences:
```diff
- // Elements with aria-disabled are not tabbable
- if (el.hasAttribute('aria-disabled') && el.getAttribute('aria-disabled') !== 'false') {
- return false;
- }
```The above was removed from `exports/tabbable.js` because `aria-disabled` elements are tabbable.
```diff
+ // Anchor tags with no hrefs arent focusable.
+ // This is focusable: Stuff
+ // This is not: Stuff
+ if ("a" === tag && el.getAttribute("href") == null) return false
```While not a big deal, anchor elements without an `href` attribute were getting tripped up.
So we added a check to make sure it has an `href`.```diff
+iframe, object, embed
```The additional elements were found here:
## Structure
`exports/` is publicly available files
`internal/` is...well...internal.`exports` and `internal` shouldn't write their own `.d.ts` that are co-located.
`types/` is where you place your handwritten `.d.ts` files.