{"id":15386252,"url":"https://github.com/konnorrogers/focus-hunter","last_synced_at":"2025-04-15T19:54:42.836Z","repository":{"id":190210404,"uuid":"682116156","full_name":"KonnorRogers/focus-hunter","owner":"KonnorRogers","description":"A focus trapping utility that respects shadow doms and slots","archived":false,"fork":false,"pushed_at":"2024-01-10T21:01:25.000Z","size":10956,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-15T19:54:33.337Z","etag":null,"topics":["focus","focustrap","trap"],"latest_commit_sha":null,"homepage":"https://konnorrogers.github.io/focus-hunter/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KonnorRogers.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["konnorrogers"]}},"created_at":"2023-08-23T13:28:42.000Z","updated_at":"2024-06-21T21:02:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"f3119f76-b9c2-4209-b83c-547fe1867a48","html_url":"https://github.com/KonnorRogers/focus-hunter","commit_stats":{"total_commits":64,"total_committers":1,"mean_commits":64.0,"dds":0.0,"last_synced_commit":"99b4d061db8982f0a0f85488205cb83d78dd2c8f"},"previous_names":["konnorrogers/focus-hunter"],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonnorRogers%2Ffocus-hunter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonnorRogers%2Ffocus-hunter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonnorRogers%2Ffocus-hunter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonnorRogers%2Ffocus-hunter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KonnorRogers","download_url":"https://codeload.github.com/KonnorRogers/focus-hunter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249145296,"owners_count":21219966,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["focus","focustrap","trap"],"created_at":"2024-10-01T14:48:26.600Z","updated_at":"2025-04-15T19:54:42.807Z","avatar_url":"https://github.com/KonnorRogers.png","language":"JavaScript","funding_links":["https://github.com/sponsors/konnorrogers"],"categories":[],"sub_categories":[],"readme":"![Bundle Size Badge](https://deno.bundlejs.com/?q=focus-hunter\u0026badge)\n\n## Purpose\n\nFocus trapping made easy for things like Dialogs.\n\n## Why?\n\nBecause focus trapping sucks. But its a necessary evil.\n\n## Demo\n\n\u003chttps://konnorrogers.github.io/focus-hunter\u003e\n\n## Prior Art\n\n- [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.\n\n- This solution has been largely extracted from [Shoelace](https://shoelace.style)\n\n## Differences from Focus Trap\n\nFocus Hunter doesn't aim to do everything. It tries its best to keep a small minimal API and get out of your way.\nThis is reflected in bundle size.\n\n`focus-hunter` is `~1.5kb` minified + gzipped.\n`focus-trap` is `~5.5kb` minified + gzipped.\n\n## Installation\n\n```bash\nnpm install focus-hunter\n```\n\n## Adding a trap\n\n\n```js\n// Create a trap\nconst trap = new Trap({ rootElement: document.querySelector(\"my-trap\") })\n\n// Start the trap\ntrap.start()\n\n// Stop the trap\ntrap.stop()\n```\n\n## All Options\n\n```js\nconst trap = new Trap({\n  rootElement,\n  preventScroll, // Passed to `element.focus({ preventScroll })` for programmatically focused elements\n})\n```\n\n## Multiple Traps\n\nFocus Trap is allowed to have multiple traps. It keeps track of the stacks using `window.focusHunter.trapStack` which\nis implemented via a `Set`.\n\nThere is also a stack of rootElements at `window.focusHunter.rootElementStack`\n\nThere 2 stacks are checked when you call `trap.start()` to ensure the rootElement isn't already being trapped and that\nthe trap isn't already active.\n\n```js\nwindow.focusHunter.trapStack // =\u003e Set\nwindow.focusHunter.rootElementStack // =\u003e Set\n```\n\n## A note on iframes\n\nWhile the focus trap can get to an `\u003ciframe\u003e` it cannot find elements within a cross origin iframe\nso they are excluded from the focus trap.\n\n## Differences from Shoelace\n\nThis library is largely me experimenting with generators. Beyond internal implementation details, here are some differences:\n\n```diff\n- // Elements with aria-disabled are not tabbable\n- if (el.hasAttribute('aria-disabled') \u0026\u0026 el.getAttribute('aria-disabled') !== 'false') {\n-   return false;\n- }\n```\n\nThe above was removed from `exports/tabbable.js` because `aria-disabled` elements are tabbable.\n\n\n```diff\n+  // Anchor tags with no hrefs arent focusable.\n+  // This is focusable: \u003ca href=\"\"\u003eStuff\u003c/a\u003e\n+  // This is not: \u003ca\u003eStuff\u003c/a\u003e\n+  if (\"a\" === tag \u0026\u0026 el.getAttribute(\"href\") == null) return false\n```\n\nWhile not a big deal, anchor elements without an `href` attribute were getting tripped up.\nSo we added a check to make sure it has an `href`.\n\n```diff\n+iframe, object, embed\n```\n\nThe additional elements were found here: \u003chttps://github.com/gdkraus/accessible-modal-dialog/blob/d2a9c13de65028cda917279246346a277509fda0/modal-window.js#L38\u003e\n\n## Structure\n\n`exports/` is publicly available files\n`internal/` is...well...internal.\n\n`exports` and `internal` shouldn't write their own `.d.ts` that are co-located.\n\n`types/` is where you place your handwritten `.d.ts` files.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkonnorrogers%2Ffocus-hunter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkonnorrogers%2Ffocus-hunter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkonnorrogers%2Ffocus-hunter/lists"}