{"_id":"@bento/dismiss","_rev":"2-9237d0f2ba84e9fe669571aedb918c1f","name":"@bento/dismiss","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@bento/dismiss","version":"0.1.0","keywords":["accessibility","aria","bento","component","dismiss","library","modal","react"],"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","_id":"@bento/dismiss@0.1.0","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":"8de511bb6b895c8c3cf3122f10b85f39f580da8b","tarball":"https://registry.npmjs.org/@bento/dismiss/-/dismiss-0.1.0.tgz","fileCount":11,"integrity":"sha512-FSPl1sXwDa2OCAi7aZ4Gm97hX6TMHZnpIdTREylxWEpJps5QmK1/9c3w1/46gFdErHtX0vfD/4IpGOsbr4NO4g==","signatures":[{"sig":"MEUCIQDgIX1sZvfftoJpRi+97GpvCrkBD5Duqc4Z8Fm/RwqH1AIgD5PWaq2fuwr2rcItxpzH+cA3m3WE6WflAw7GESjBOXQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bento%2fdismiss@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":43516},"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":"Dismiss button component for accessible modal dismissal","directories":{},"_nodeVersion":"23.11.1","dependencies":{"@bento/slots":"^0.2.0","@bento/container":"^0.2.0","@bento/use-props":"^0.2.0","@bento/visually-hidden":"^0.1.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"react":"18.x || 19.x","react-dom":"18.x || 19.x","react-aria":"^3.29.0"},"_npmOperationalInternal":{"tmp":"tmp/dismiss_0.1.0_1764862962855_0.20307807495199914","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@bento/dismiss","version":"0.1.1","description":"Dismiss button component for accessible modal dismissal","type":"module","main":"./dist/index.cjs","module":"./dist/index.js","scripts":{"build":"tsup-node","lint":"biome lint && tsc","posttest":"npm run lint","prepublishOnly":"node ../../scripts/compile-readme.ts","pretest":"npm run build","test":"vitest --run","test:watch":"vitest"},"repository":{"type":"git","url":"git+https://github.com/godaddy/bento.git"},"keywords":["accessibility","aria","bento","component","dismiss","library","modal","react"],"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","bugs":{"url":"https://github.com/godaddy/bento/issues"},"homepage":"https://github.com/godaddy/bento#readme","dependencies":{"@bento/container":"^0.2.1","@bento/slots":"^0.3.0","@bento/use-props":"^0.2.1","@bento/visually-hidden":"^0.1.1"},"peerDependencies":{"react":"18.x || 19.x","react-dom":"18.x || 19.x","react-aria":"^3.29.0"},"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"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"gitHead":"0f8ba63cf8539136795958006c36d1aee1f70d8e","types":"./dist/index.d.ts","_id":"@bento/dismiss@0.1.1","_nodeVersion":"23.11.1","_npmVersion":"11.7.0","dist":{"integrity":"sha512-rVQsgi019X6WkL0P4ywxSogpFKy5M3arFiHjvOCvbOf6a8EPt+zq49Q4BpDKCa5Jp1EjXzpYAt6XA/i/tD66rg==","shasum":"189166f30d5de93c058ce14287f3ae797dbfc7c2","tarball":"https://registry.npmjs.org/@bento/dismiss/-/dismiss-0.1.1.tgz","fileCount":11,"unpackedSize":43516,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@bento%2fdismiss@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIH5sZq4X3Kx/iCd3jS+A5PzVhm+5Upq3kSdRpNwql3wUAiEA+zB1Lz1Z++De7ePcgzwwRnOWBOJia7qu1icFFVAPxy4="}]},"_npmUser":{"name":"rxmarbles","email":"rmarkins@gmail.com"},"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/dismiss_0.1.1_1766075442207_0.2711757476054262"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-04T15:42:42.762Z","modified":"2025-12-18T16:30:42.859Z","0.1.0":"2025-12-04T15:42:43.010Z","0.1.1":"2025-12-18T16:30:42.371Z"},"bugs":{"url":"https://github.com/godaddy/bento/issues"},"author":{"name":"GoDaddy Operating Company, LLC"},"license":"MIT","homepage":"https://github.com/godaddy/bento#readme","keywords":["accessibility","aria","bento","component","dismiss","library","modal","react"],"repository":{"type":"git","url":"git+https://github.com/godaddy/bento.git"},"description":"Dismiss button component for accessible modal dismissal","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":"import {\n  Meta,\n  Story,\n  ArgTypes,\n  Controls,\n  Source,\n} from '@storybook/addon-docs/blocks';\n\n# Dismiss\n\nThe `@bento/dismiss` package provides an accessible, visually hidden dismissal\ncontrol for overlays and popup content. It ensures users, especially those using\nscreen readers, can reliably dismiss modal dialogs, drawers, and popovers\nthrough linear keyboard navigation. This component complements ESC key handling\nand outside-click behaviors, filling a critical accessibility gap when sighted\nusers have a visible close button but screen reader users navigating linearly\nencounter no dismissal affordance.\n\nThis primitive aligns with React Aria's DismissButton pattern and should be\npositioned at both the start and end of dismissible overlay content. When a\nscreen reader user navigates forward or backward through an overlay, they will\nencounter these controls, giving them a clear way to exit the overlay without\nrelying solely on the ESC key or outside-click patterns that may not be\ndiscoverable through linear navigation.\n\n## Installation\n\n```shell\nnpm install --save @bento/dismiss\n```\n\n## Props\n\nThe `@bento/dismiss` package exports the `Dismiss` component:\n\n```jsx\nimport { Dismiss } from '@bento/dismiss';\n\n<Dismiss onDismiss={() => setOpen(false)} />\n```\n\nThe following properties are available to be used on the `Dismiss` component:\n\n| Prop | Type | Required | Description |\n|------|------|----------|------------|\n| `onDismiss` | `() => void` | No | Called when the dismiss button is activated. |\n| `ariaLabel` | `string` | No | Accessible label for the dismiss button. Should be localized. |\n| `children` | `ReactNode` | No | The content to render inside the container. |\n| `slots` | `{ hidden?: ((args: { props: Record<string, unknown>; children: ReactNode; }) => ReactNode) \\| Record<string, unknown>; } & Record<string, object \\| Function>` | No | Optional slot to customize the VisuallyHidden wrapper.\nAn object that contains the customizations for the slots.\nThe main way you interact with the slot system as a consumer. |\n| `slot` | `string` | 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\nFor all other properties specified on the `Dismiss` component, the component\nwill pass them down to the underlying button element. This includes properties\nsuch as `id`, `data-*` attributes, or additional ARIA attributes that you might\nneed for specialized use cases.\n\n### Example\n\n<Source language='tsx' code={ SourceBasic } />\n\n## Examples\n\n### Basic Usage\n\nThe most common pattern for the `Dismiss` component is to place it at both the\nstart and end of dismissible overlay content. This ensures screen reader users\nnavigating forward encounter a dismissal control at the beginning, and users\nnavigating backward from content below the overlay encounter a dismissal control\nat the end.\n\n<Source language='tsx' code={ SourceBasic } />\n\nIn this example, when a screen reader user navigates into the dialog, they\nimmediately encounter the first dismiss button. If they navigate through all the\ncontent and continue forward, they encounter the second dismiss button before\nexiting the overlay's focus boundary. Both buttons invoke the same `onDismiss`\ncallback to close the dialog.\n\n### Custom Label\n\nThe default accessible label is \"Dismiss\". For localization or context-specific\nlabeling, use the `ariaLabel` prop to provide a custom label that makes sense in\nyour application's language and terminology.\n\n<Source language='tsx' code={ SourceCustomLabel } />\n\nProviding clear, localized labels helps screen reader users understand what will\nhappen when they activate the dismiss button. Use labels that match the\nterminology of your application, such as \"Close dialog\", \"Exit menu\", or\n\"Dismiss notification\".\n\n## Usage Guidelines\n\nUnderstanding when and where to use the `Dismiss` component is critical for\ncreating accessible overlay patterns. The following guidance is based on React\nAria patterns and WCAG accessibility standards.\n\n### Required Usage\n\nThe `Dismiss` component is required in the following contexts:\n\n**Modal Dialogs and Overlays**\n\nWhen creating modal dialogs that block interaction with the rest of the page,\nplace a `Dismiss` control at the start and end of the dialog content. This\nprovides screen reader users with a reliable dismissal mechanism regardless of\nwhether they navigate forward or backward through the content. While sighted\nusers can click a visible close button, screen reader users navigating linearly\nneed an equivalent affordance at both boundaries.\n\n**Modal Drawers and Sheets**\n\nSide panels and bottom sheets that use modal behavior should follow the same\npattern as modal dialogs. Position dismiss controls at the boundaries of the\ndrawer content to ensure users can exit through linear navigation.\n\n### Recommended Usage\n\nThe `Dismiss` component is recommended but not strictly required in these\ncontexts:\n\n**Dismissible Popovers and Menus**\n\nWhen popovers or dropdown menus can be dismissed but lack a visible close\nbutton, include start and end dismiss controls. This ensures screen reader users\ncan exit the popup even when ESC key handling might not be discoverable.\n\n**Coachmarks and Tour Steps**\n\nProduct tours and onboarding flows that can be dismissed should include dismiss\ncontrols. If the tour requires explicit action buttons to proceed, consider\nwhether a generic dismiss is appropriate or whether users should be guided\nthrough specific actions.\n\n**Combobox and Select Popovers**\n\nWhile combobox popovers typically manage focus automatically, adding dismiss\ncontrols can help screen reader users who want to exit the popup without making\na selection.\n\n### Not Recommended\n\nDo not use the `Dismiss` component in these contexts:\n\n**Tooltips**\n\nTooltips are non-interactive content that appear on hover or focus and do not\ntrap focus. They do not need dismiss controls as users can simply navigate away\nfrom the trigger element.\n\n**Toasts and Notifications**\n\nToast notifications and growl-style messages typically do not trap focus and\nshould not use the `Dismiss` component. If dismissal is needed, provide a\nvisible close button instead.\n\n**Non-Dismissible Content**\n\nLegal consent dialogs, age gates, or other content that requires explicit user\naction should use specific action buttons rather than a generic dismiss control.\n\n### Placement Rules\n\nFollow these guidelines for correct placement:\n\nPosition the first dismiss control immediately after the opening tag of your\noverlay content container, before any other focusable elements. Position the\nsecond dismiss control immediately before the closing tag of your overlay\ncontent container, after all other focusable elements. This ensures linear\nnavigation always encounters a dismiss affordance at the boundaries.\n\nAlways maintain a visible close button for sighted users. The `Dismiss`\ncomponent is a screen reader affordance, not a replacement for visible UI\ncontrols. Sighted keyboard users and mouse users need their own clear way to\nclose overlays.\n\nUse meaningful, localized labels through the `ariaLabel` prop. The default\n\"Dismiss\" may not be appropriate for all contexts or languages. Consider labels\nlike \"Close dialog\", \"Exit menu\", or region-specific translations that match\nyour application's terminology.\n\n## Accessibility\n\nThe `Dismiss` component is designed with accessibility as its primary purpose.\nIt fills a specific gap in overlay accessibility by providing a dismissal\naffordance for users navigating with screen readers using linear navigation\npatterns.\n\n**Screen Reader Compatibility**\n\nThe component uses the `@bento/visually-hidden` primitive to ensure the button\nremains completely accessible to assistive technologies while being visually\nhidden from sighted users. This technique uses CSS to position content\noff-screen rather than using `display: none` or `visibility: hidden`, which\nwould make the content unavailable to screen readers.\n\n**Keyboard Navigation**\n\nThe dismiss button is fully keyboard accessible. Screen reader users can\nactivate it using Enter or Space when focused on the element. The component uses\n`tabIndex={-1}` which removes the button from the standard tab order but allows\nscreen readers to navigate to it through virtual cursor navigation. This is the\nstandard pattern for this type of control and aligns with React Aria's\nDismissButton implementation.\n\n**ARIA Labeling**\n\nThe component applies `aria-label` to provide context about what the button\ndoes. The default label is \"Dismiss\", but you should customize this through the\n`ariaLabel` prop to match your application's terminology and language. Clear,\ndescriptive labels help screen reader users understand the button's purpose\nwithout requiring additional context.\n\n**Semantic HTML**\n\nThe component renders as a native HTML `button` element with `type=\"button\"` to\nprevent accidental form submission. Using semantic HTML ensures compatibility\nwith assistive technologies and provides the expected button semantics and\nkeyboard behavior automatically.\n\n**Integration with Overlay Patterns**\n\nThe `Dismiss` component is designed to work alongside other accessibility\nfeatures in overlay patterns. It complements ESC key handling from React Aria's\noverlay hooks, outside-click dismissal through `OverlayTrigger`, and focus\ncontainment from focus management utilities. While these features provide\ndismissal mechanisms for some users, the `Dismiss` component specifically\naddresses the needs of screen reader users navigating linearly through content.\n\nPosition the component inside your overlay's focus boundary, within the same\ncontainer as your overlay content. It should be rendered before and after your\noverlay's main content to ensure users encounter it when navigating in either\ndirection.\n\n## Customization\n\nThe `Dismiss` component is built using the `@bento/slots` package, allowing you\nto customize specific parts of the component through slot-based composition.\nWhile the component is intentionally visually hidden, understanding its\ncustomization options can be useful for specialized use cases or debugging.\n\n### Slots\n\nThe component is registered as `BentoDismiss` and introduces the following slots:\n\n- `hidden`: Assigned to the `@bento/visually-hidden` component that wraps the dismiss button.\n\nYou can use the `slots` prop to override the default behavior of the visually hidden wrapper:\n\n<Source language='tsx' code={ SourceSlotCustomization } />\n\nIn this example, we override the `hidden` slot to provide custom styling to the\nvisually hidden wrapper. While this is possible, it is rarely necessary in\npractice since the component is designed to be visually hidden by default.\n\nSee the `@bento/slots` package for more information on how to use the `slot` and\n`slots` properties.\n\n### Styling\n\nWhile the dismiss button is visually hidden by default and styling is typically\nnot necessary, you can customize the underlying button element using `className`\nor `style` props. These props will be applied to the button element itself, not\nthe visually hidden wrapper.\n\n```jsx\nimport { Dismiss } from '@bento/dismiss';\n\n<Dismiss onDismiss={handleDismiss} className=\"my-dismiss-button\" />\n```\n\nWhen you assign a `className` to the component, you take full responsibility for\nstyling. The component will pass this className to the button element, allowing\nyou to target it with CSS selectors. However, keep in mind that because the\nbutton is wrapped in a visually hidden container, visual styles will not be\nvisible to sighted users.\n\n### Data Attributes\n\nThe following data attributes are automatically applied to the component:\n\n| Attribute     | Description                                                                  | Example Values |\n| ------------- | ---------------------------------------------------------------------------- | -------------- |\n| `data-hidden` | Applied to the visually hidden wrapper, indicating content is accessible to screen readers | \"true\"         |\n\nThese attributes are provided by the underlying `@bento/visually-hidden`\ncomponent and can be used for debugging or specialized styling scenarios:\n\n```css\n[data-hidden=\"true\"] button[type=\"button\"] {\n  /* Target all visually hidden buttons */\n}\n```\n\n### Default Attributes\n\nThe component renders a native `button` element with the following attributes:\n\n- `type=\"button\"`: Prevents the button from submitting forms when used inside\n  form elements.\n- `tabIndex={-1}`: Removes the button from the standard tab order while keeping\n  it accessible to screen readers through virtual cursor navigation.\n- `aria-label`: Provides an accessible label for screen readers. Defaults to\n  \"Dismiss\" but can be customized via the `ariaLabel` prop.\n- `style={{ width: 1, height: 1 }}`: A defensive fallback that ensures the button\n  has minimal dimensions even when visually hidden, which can help with screen\n  reader detection in certain scenarios.","readmeFilename":"README.md"}