{"_id":"@bento/focus-lock","_rev":"3-24536106aec569e0aff15294316416fa","name":"@bento/focus-lock","dist-tags":{"latest":"0.0.3"},"versions":{"0.0.1":{"name":"@bento/focus-lock","version":"0.0.1","keywords":["accessibility","aria","bento","component","focus","focus-lock","focus-scope","focus-trap","library","react"],"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","_id":"@bento/focus-lock@0.0.1","maintainers":[{"name":"3rdeden","email":"npmjs@3rd-Eden.com"},{"name":"rxmarbles","email":"rmarkins@gmail.com"},{"name":"kawikabader","email":"ekbader@gmail.com"}],"homepage":"https://github.com/godaddy/bento#readme","bugs":{"url":"https://github.com/godaddy/bento/issues"},"dist":{"shasum":"2c55e3ab8347872d68a3002f34c9fe63dc5d5c15","tarball":"https://registry.npmjs.org/@bento/focus-lock/-/focus-lock-0.0.1.tgz","fileCount":11,"integrity":"sha512-w49JUtylvxk4H2vhdTyZOSMsL0wZPIlfo9UqzT9GLaDIQqub6XFCP/BeENsQ155hHZZboesgz/YVcC21NtX/ZA==","signatures":[{"sig":"MEYCIQDQBWdBkLe/tS7dutz34ap+HUSOYtuYkQ3NClxLOE/7RQIhAO196J7xpinvrW6f9IN2cMWCYT2V5h+YjBaWOaHhJOw/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bento%2ffocus-lock@0.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":41730},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"gitHead":"2552a8442bd7e504706233eeb501001087058cdf","scripts":{"lint":"biome lint && tsc","test":"vitest --run","build":"tsup-node","pretest":"npm run build","posttest":"npm run lint","test:watch":"vitest","prepublishOnly":"node ../../scripts/compile-readme.ts"},"_npmUser":{"name":"kawikabader","email":"ekbader@gmail.com"},"repository":{"url":"git+https://github.com/godaddy/bento.git","type":"git"},"_npmVersion":"11.6.4","description":"Focus lock primitive for managing focus within a scope","directories":{},"_nodeVersion":"23.11.1","dependencies":{"@bento/slots":"^0.2.0","@bento/use-props":"^0.2.0","@react-aria/focus":"^3.18.6","@react-aria/interactions":"^3.22.6","@bento/use-data-attributes":"^0.1.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"@bento/text":"*","@bento/radio":"*","@bento/button":"*","@bento/heading":"*","@bento/listbox":"*","@bento/container":"*"},"peerDependencies":{"react":"18.x || 19.x","react-dom":"18.x || 19.x"},"_npmOperationalInternal":{"tmp":"tmp/focus-lock_0.0.1_1764862962816_0.43832661914431936","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@bento/focus-lock","version":"0.0.2","keywords":["accessibility","aria","bento","component","focus","focus-lock","focus-scope","focus-trap","library","react"],"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","_id":"@bento/focus-lock@0.0.2","maintainers":[{"name":"rmarkins","email":"rmarkins@godaddy.com"},{"name":"3rdeden","email":"npmjs@3rd-Eden.com"},{"name":"rxmarbles","email":"rmarkins@gmail.com"},{"name":"kawikabader","email":"ekbader@gmail.com"}],"homepage":"https://github.com/godaddy/bento#readme","bugs":{"url":"https://github.com/godaddy/bento/issues"},"dist":{"shasum":"ed4d8b7a2f6580905e91ede0e8cddcc115fdd751","tarball":"https://registry.npmjs.org/@bento/focus-lock/-/focus-lock-0.0.2.tgz","fileCount":11,"integrity":"sha512-JKiuotKurd/b74K72Q/9zh0h3wWj3ymY6WaPPB+uLZUK1Bz2NZo6q14ExFPvAIucrhbNNywiA1j6rBddMwqv7w==","signatures":[{"sig":"MEUCIQCG9Q205J9j3wb+QT9dA5AWZG216pq6FsybfLuJavRvtgIgCoMOxTiaU2zZroQpLYRMUnpXwOkpxpWx3ZZgcVsJrjc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bento%2ffocus-lock@0.0.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":41730},"main":"./dist/index.cjs","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"gitHead":"0f8ba63cf8539136795958006c36d1aee1f70d8e","scripts":{"lint":"biome lint && tsc","test":"vitest --run","build":"tsup-node","pretest":"npm run build","posttest":"npm run lint","test:watch":"vitest","prepublishOnly":"node ../../scripts/compile-readme.ts"},"_npmUser":{"name":"rxmarbles","email":"rmarkins@gmail.com"},"repository":{"url":"git+https://github.com/godaddy/bento.git","type":"git"},"_npmVersion":"11.7.0","description":"Focus lock primitive for managing focus within a scope","directories":{},"_nodeVersion":"23.11.1","dependencies":{"@bento/slots":"^0.3.0","@bento/use-props":"^0.2.1","@react-aria/focus":"^3.18.6","@react-aria/interactions":"^3.22.6","@bento/use-data-attributes":"^0.1.1"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"devDependencies":{"@bento/text":"*","@bento/radio":"*","@bento/button":"*","@bento/heading":"*","@bento/listbox":"*","@bento/container":"*"},"peerDependencies":{"react":"18.x || 19.x","react-dom":"18.x || 19.x"},"_npmOperationalInternal":{"tmp":"tmp/focus-lock_0.0.2_1766075441226_0.49358085431199794","host":"s3://npm-registry-packages-npm-production"}},"0.0.3":{"name":"@bento/focus-lock","version":"0.0.3","description":"Focus lock primitive for managing focus within a scope","type":"module","main":"./dist/index.cjs","module":"./dist/index.mjs","scripts":{"build":"tsdown","lint":"biome lint && tsgo --noEmit","prepublishOnly":"node ../../../scripts/compile-readme.ts","test":"vitest --run","test:watch":"vitest","typecheck":"tsgo --noEmit -p tsconfig.json"},"repository":{"type":"git","url":"git+https://github.com/godaddy/antares.git"},"keywords":["accessibility","aria","bento","component","focus","focus-lock","focus-scope","focus-trap","library","react"],"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","bugs":{"url":"https://github.com/godaddy/antares/issues"},"homepage":"https://github.com/godaddy/antares#readme","dependencies":{"@bento/slots":"^0.3.0","@bento/use-data-attributes":"^0.1.1","@bento/use-props":"^0.2.3","@react-aria/focus":"^3.22.0","@react-aria/interactions":"^3.28.0"},"devDependencies":{"@bento/button":"*","@bento/container":"*","@bento/heading":"*","@bento/listbox":"*","@bento/radio":"*","@bento/text":"*","@types/react":"^19.2.15","@types/react-dom":"^19.2.3","tsdown":"^0.22.1","typescript":"^6.0.3","vitest":"^4.1.7","vitest-browser-react":"^2.2.0"},"peerDependencies":{"react":"18.x || 19.x","react-dom":"18.x || 19.x"},"exports":{".":{"import":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}},"./package.json":"./package.json"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"gitHead":"19c4a71618042e4c8217311365f2400575ac5d57","_id":"@bento/focus-lock@0.0.3","_nodeVersion":"24.16.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-I2OIdFXkenLH9+F+8d8nBVsJ26U4RIpKC1uHxefE8mHuxP5BsWEMPNLXOyfE1mkF2OIH7NIsdalsznq58G6U1A==","shasum":"b4063c89a98dbd487c07715664e66197dd5fd8b3","tarball":"https://registry.npmjs.org/@bento/focus-lock/-/focus-lock-0.0.3.tgz","fileCount":13,"unpackedSize":46724,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bento%2ffocus-lock@0.0.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDxotGoWwZkpkatT8YfHecKavY5Gs+2S8G7gFibA0C25AIgdO3HplXia0AqYxWLXjYGxJGPrdRHO5LOWCMbwy28XS4="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0086a408-1ba0-4f29-9318-0d32db1fe6d7"}},"directories":{},"maintainers":[{"name":"rmarkins","email":"rmarkins@godaddy.com"},{"name":"3rdeden","email":"npmjs@3rd-Eden.com"},{"name":"rxmarbles","email":"rmarkins@gmail.com"},{"name":"kawikabader","email":"ekbader@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/focus-lock_0.0.3_1780645944436_0.7461139407986566"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-04T15:42:42.714Z","modified":"2026-06-05T07:52:24.891Z","0.0.1":"2025-12-04T15:42:42.975Z","0.0.2":"2025-12-18T16:30:41.348Z","0.0.3":"2026-06-05T07:52:24.582Z"},"bugs":{"url":"https://github.com/godaddy/antares/issues"},"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","homepage":"https://github.com/godaddy/antares#readme","keywords":["accessibility","aria","bento","component","focus","focus-lock","focus-scope","focus-trap","library","react"],"repository":{"type":"git","url":"git+https://github.com/godaddy/antares.git"},"description":"Focus lock primitive for managing focus within a scope","maintainers":[{"name":"rmarkins","email":"rmarkins@godaddy.com"},{"name":"3rdeden","email":"npmjs@3rd-Eden.com"},{"name":"rxmarbles","email":"rmarkins@gmail.com"},{"name":"kawikabader","email":"ekbader@gmail.com"}],"readme":"# FocusLock\n\nThe `@bento/focus-lock` package provides focus management for containing and\ncontrolling keyboard focus within specific areas of your application. Built on\ntop of React ARIA's FocusScope, it ensures focus remains trapped within\ndesignated boundaries, making it essential for modals, dialogs, drawers, select\npopovers, and other overlay components.\n\n## Installation\n\n```shell\nnpm install --save @bento/focus-lock\n```\n\n## Props\n\nThe following properties are available to be used on the `FocusLock` component:\n\n| Prop | Type | Required | Description |\n|------|------|----------|------------|\n| `contain` | `boolean \\| undefined` | No | Whether to contain focus within the scope.\nWhen true, focus will cycle between focusable elements within the scope. |\n| `restoreFocus` | `boolean \\| undefined` | No | Whether to restore focus to the previously focused element when the focus scope unmounts. |\n| `autoFocus` | `boolean \\| undefined` | No | Whether to automatically focus the first focusable element when the focus scope mounts. |\n| `children` | `ReactNode` | No | The content to render inside the focus lock.\nCan be a single element or multiple elements. |\n| `onFocusEnter` | `((e: FocusEvent<Element, Element>) => void) \\| undefined` | No | Callback fired when focus enters the scope |\n| `onFocusLeave` | `((e: FocusEvent<Element, Element>) => void) \\| undefined` | No | Callback fired when focus leaves the scope |\n| `className` | `string \\| ((state: FocusLockState) => string) \\| undefined` | No | Render prop for className |\n| `style` | `((state: FocusLockState) => CSSProperties) \\| CSSProperties \\| undefined` | No | Render prop for style |\n| `slot` | `string \\| undefined` | No | A named part of a component that can be customized. This is implemented by the consuming component.\nThe exposed slot names of a component are available in the components documentation. |\n| `slots` | `Record<string, object \\| Function> \\| undefined` | No | An object that contains the customizations for the slots.\nThe main way you interact with the slot system as a consumer. |\n\nFor all other properties specified on the `FocusLock` component, they will be\npassed down to the underlying React ARIA FocusScope component.\n\n## Examples\n\nThe simplest use case is to wrap your modal or dialog content with `FocusLock`\nand enable focus containment.\n\n<Source language='tsx' code={ SourceBasic } />\n\nFocus scopes can be nested, allowing you to have multiple layers of focus\ncontainment. When a nested scope is active, focus is trapped within the\ninnermost scope.\n\n<Source language='tsx' code={ SourceNested } />\n\nThe `FocusLock` component applies data attributes directly to its children\nwithout introducing a wrapper element. This example demonstrates multiple\nchildren (backdrop and content).\n\n<Source language='tsx' code={ SourceOverlay } />\n\nWhen used with a single child, the focus lock applies data attributes to that child element.\n\n<Source language='tsx' code={ SourceSelect } />\n\nFocus lock is particularly useful for multi-step forms where you want to keep focus within the current step.\n\n<Source language='tsx' code={ SourceForm } />\n\n## Customization\n\nThe `FocusLock` component is created using the `@bento/slots` package and allows\nassignment of the custom `slot` property for overrides. The component applies\nprops to the underlying React ARIA `FocusScope` component and data attributes to\nits children.\n\n### Slots\n\nThe `@bento/focus-lock` component is registered as `BentoFocusLock` and can be\ncustomized using the slot system. See the `@bento/slots` package for more\ninformation on how to use the `slot` and `slots` properties.\n\nRender prop function receives a state object with the following properties:\n\n```typescript\ninterface FocusLockState {\n  hasFocus: boolean;      // Whether focus is currently within the scope\n  isContained: boolean;   // Whether focus is contained (same as contain prop)\n}\n```\n\n### Data Attributes\n\nThe following data attributes are automatically applied to the children of the `FocusLock` component:\n\n| Attribute              | Description                                      | Example Values  |\n| ---------------------- | ------------------------------------------------ | --------------- |\n| `data-focus-contained` | Indicates whether focus is contained             | \"true\" / \"false\"|\n| `data-has-focus`       | Indicates whether the scope currently has focus  | \"true\" / \"false\"|\n\nThese data attributes can be targeted using CSS selectors for styling. When\nusing data attributes for styling, ensure you scope them properly with a\nclassName to avoid affecting unrelated elements:\n\n```css\n.my-modal[data-focus-contained=\"true\"] {\n  outline: 2px solid blue;\n}\n\n.my-modal[data-has-focus=\"true\"] {\n  background-color: rgba(0, 0, 0, 0.05);\n}\n```\n\nApply the scoping className to your FocusLock children:\n\n```tsx\n<FocusLock contain restoreFocus autoFocus>\n  <div className=\"my-modal\">\n    Modal content\n  </div>\n</FocusLock>\n```\n\n## Accessibility\n\nFocus management is crucial for accessibility. The `FocusLock` component ensures\nthat keyboard users can navigate within the focus scope using Tab and Shift+Tab,\nfocus is trapped within the scope when `contain` is enabled, focus is\nautomatically restored to the previously focused element when the scope is\nremoved (when `restoreFocus` is enabled), and the first focusable element is\nautomatically focused when the scope is mounted (when `autoFocus` is enabled).\n\nWhen using focus lock, follow these accessibility guidelines:\n\n- Always provide a way to exit the focus scope (e.g., a close button or escape key handler)\n- Use `restoreFocus` to ensure users return to their previous location when the scope is closed\n- Use `autoFocus` to immediately draw attention to important content like modals\n- Consider using `aria-modal` on modal dialogs to provide additional context to screen readers\n- Ensure all focusable elements within the scope are keyboard accessible","readmeFilename":"README.md"}