
Company News
Meet the Socket Team at RSAC and BSidesSF 2026
Join Socket for live demos, rooftop happy hours, and one-on-one meetings during BSidesSF and RSA 2026 in San Francisco.
@bento/overlay
Advanced tools
Overlay primitive for creating layered UI experiences like modals, drawers, and popups
The @bento/overlay package provides the Overlay component, a foundational
primitive for creating layered UI experiences where content appears above the
main application view. Overlay manages state and coordinates React Aria hooks,
passing props via slots to children for flexible composition.
Overlay serves as a coordinator that brings together focused primitives like Portal, FocusLock, ScrollLock, and Dismiss. It handles state management and React Aria integration while delegating rendering and behavior to composed primitives.
Overlay addresses several key scenarios:
npm install --save @bento/overlay @bento/portal @bento/focus-lock @bento/scroll-lock @bento/dismiss
The @bento/overlay package exports the Overlay component:
| Prop | Type | Required | Description |
|---|---|---|---|
slots | Record<string, object | Function> & { trigger?: TriggerSlotValue; } | No | Slot overrides for the overlay. |
| The trigger slot is typed to expose React Aria press handlers so consumers | |||
| are guided toward using pressable-aware primitives (e.g. | |||
| @bento /button). | |||
open | boolean | No | Whether the overlay is open (controlled). |
defaultOpen | boolean | No | Default open state (uncontrolled). |
onOpenChange | (open: boolean) => void | No | Callback fired when open state changes. |
type | "dialog" | "menu" | "listbox" | "tree" | "grid" | No | The type of overlay trigger. |
isDismissable | boolean | No | Whether the overlay can be dismissed by clicking outside or pressing ESC. |
children | ReactNode | No | Content to render inside the overlay. |
| Consumers provide Portal, ScrollLock, FocusLock, and content via slots. | |||
slot | string | No | A named part of a component that can be customized. This is implemented by the consuming component. |
| The exposed slot names of a component are available in the components documentation. |
The simplest overlay usage demonstrates controlled state management:
<Source language='tsx' code={ SourceBasic } />
A complete modal dialog combining all overlay primitives. This example demonstrates best practices for accessible modal patterns using Portal for DOM rendering, ScrollLock for background scroll prevention, FocusLock for focus containment, and Dismiss for screen reader accessibility:
<Source language='tsx' code={ SourceModal } />
Drawers use the same overlay primitives as modals but with different positioning. This example shows a drawer sliding in from the right side:
<Source language='tsx' code={ SourceDrawer } />
An uncontrolled overlay that manages its own state internally. The trigger button uses the trigger slot to receive toggle handlers from the Overlay component:
<Source language='tsx' code={ SourceUncontrolled } />
A lightweight popover without ScrollLock or backdrop, suitable for non-blocking UI elements:
<Source language='tsx' code={ SourcePopover } />
Overlay follows Bento's composition model by managing state and passing handlers via slots to children. It does not render DOM elements itself but coordinates the behavior of composed primitives.
Overlay passes props to children through the slot system. Children with slot assignments automatically receive the appropriate props:
| Slot | Purpose | Props Provided | Required |
|---|---|---|---|
trigger | Element that opens/closes the overlay | triggerProps from React Aria (requires a pressable component) | No |
backdrop | Visual backdrop behind content | overlayProps from React Aria | No |
content | Main overlay content container | overlayProps from React Aria | Yes |
Note: The trigger slot must be filled with a component that consumes React Aria press events (for example
@bento/buttonor any primitive built on@bento/pressable). Passing a raw DOM element (e.g.Container as="button") leaves theonPresshandler on the native element, which React ignores and will log warnings.
The recommended overlay structure follows this hierarchy:
Overlay (state management, coordination)
├─ Trigger (slot="trigger", optional)
└─ Portal (DOM rendering location, when open)
├─ ScrollLock (background scroll prevention)
├─ Backdrop (slot="backdrop", optional, for modal overlays)
└─ FocusLock (focus trapping and restoration)
└─ Content (slot="content", user-provided content)
├─ Dismiss (accessible dismiss at start)
├─ User content (Text, buttons, etc.)
└─ Dismiss (accessible dismiss at end)
Overlay supports both controlled and uncontrolled state management using React
Aria's useOverlayTriggerState hook.
Controlled - Parent component manages state:
const [open, setOpen] = useState(false);
<Overlay open={open} onOpenChange={setOpen}>
{/* content */}
</Overlay>
Uncontrolled - Overlay manages state internally:
<Overlay defaultOpen={false}>
<Button slot="trigger">Open</Button>
{/* content */}
</Overlay>
Overlay integrates React Aria's overlay hooks to provide accessible behavior:
The component passes React Aria hook return values to children via slots, allowing consumers to manually compose primitives while maintaining proper accessibility.
Overlay is designed with accessibility as a foundation:
State Management
Focus Management
Keyboard Support
Screen Reader Support
Overlay applies the following data attribute to help with styling and testing:
| Attribute | Description | Example Values |
|---|---|---|
data-state | Current open state | "open" / "closed" |
These attributes are passed via the Box context to children, allowing styling based on overlay state:
.my-overlay [slot="content"][data-state="open"] {
animation: fadeIn 200ms ease-in;
}
.my-overlay [slot="backdrop"][data-state="open"] {
animation: fadeIn 200ms ease-in;
}
Overlay is designed to work with these Bento primitives:
Overlay is SSR-safe and works correctly in server-side rendering environments. The component only manages state and does not attempt to access browser APIs. Ensure composed primitives like Portal are properly configured for SSR.
Overlay supports all modern browsers through React Aria's cross-browser compatibility layer. The component handles platform-specific behavior transparently.
Overlay is created using the @bento/slots package via
withSlots('BentoOverlay', ...), which means it supports the standard slot
and slots props for integration with parent components.
Overlay defines three slot assignments that children can use to receive overlay-specific props:
trigger: Receives trigger props from useOverlayTriggerbackdrop: Receives overlay props for backdrop interactionscontent: Receives overlay props for content containerSee the @bento/slots package for more information on how to use the slot and slots properties.
Since Overlay doesn't render DOM elements itself, styling is applied to composed
children. Use the className or style props on Portal children, or target
elements using data attributes:
<Overlay open={open} onOpenChange={setOpen}>
<Container slot="backdrop" className="my-backdrop" />
<Container slot="content" className="my-content">
{/* content */}
</Container>
</Overlay>
CSS targeting:
.my-backdrop[data-state="open"] {
animation: fadeIn 200ms;
}
.my-content[data-state="open"] {
animation: slideUp 300ms;
}
Always provide a way to close: Ensure users can dismiss overlays via backdrop click, ESC key, close button, or Dismiss controls.
Use appropriate patterns: Modal overlays should use FocusLock and ScrollLock. Non-modal popovers may skip these primitives for lightweight interactions.
Position carefully: Use Portal to avoid clipping issues. Consider viewport boundaries and scrolling when positioning overlay content.
Manage focus: Always use FocusLock with restoreFocus for modal patterns to ensure focus returns to the trigger.
Screen reader accessibility: Include Dismiss controls at start and end of modal content for users navigating linearly.
Semantic HTML: Use appropriate heading levels and ARIA labels within overlay content.
Overlay is lightweight and only manages state and context. Performance characteristics depend on composed children. Use conditional rendering to avoid mounting Portal, FocusLock, and other primitives when the overlay is closed.
FAQs
Overlay primitive for creating layered UI experiences like modals, drawers, and popups
The npm package @bento/overlay receives a total of 2 weekly downloads. As such, @bento/overlay popularity was classified as not popular.
We found that @bento/overlay demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Join Socket for live demos, rooftop happy hours, and one-on-one meetings during BSidesSF and RSA 2026 in San Francisco.

Research
/Security News
Malicious Packagist packages disguised as Laravel utilities install an encrypted PHP RAT via Composer dependencies, enabling remote access and C2 callbacks.

Research
/Security News
OpenVSX releases of Aqua Trivy 1.8.12 and 1.8.13 contained injected natural-language prompts that abuse local AI coding agents for system inspection and potential data exfiltration.