Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

@bento/overlay

Package Overview
Dependencies
Maintainers
0
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bento/overlay

Overlay primitive for creating layered UI experiences like modals, drawers, and popups

latest
Source
npmnpm
Version
0.1.1
Version published
Maintainers
0
Created
Source

Overlay

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.

Purpose

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.

Use Cases

Overlay addresses several key scenarios:

  • Modal dialogs: Displaying content that requires immediate user attention
  • Drawers and sheets: Side panels or bottom sheets common in mobile interfaces
  • Loading states: Fullscreen loading indicators that block interaction
  • Image viewers: Lightbox-style image viewing experiences
  • Onboarding flows: Step-by-step tutorials that overlay the application

Installation

npm install --save @bento/overlay @bento/portal @bento/focus-lock @bento/scroll-lock @bento/dismiss

Props

The @bento/overlay package exports the Overlay component:

PropTypeRequiredDescription
slotsRecord<string, object | Function> & { trigger?: TriggerSlotValue; }NoSlot 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).
openbooleanNoWhether the overlay is open (controlled).
defaultOpenbooleanNoDefault open state (uncontrolled).
onOpenChange(open: boolean) => voidNoCallback fired when open state changes.
type"dialog" | "menu" | "listbox" | "tree" | "grid"NoThe type of overlay trigger.
isDismissablebooleanNoWhether the overlay can be dismissed by clicking outside or pressing ESC.
childrenReactNodeNoContent to render inside the overlay.
Consumers provide Portal, ScrollLock, FocusLock, and content via slots.
slotstringNoA 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.

Examples

Basic Usage

The simplest overlay usage demonstrates controlled state management:

<Source language='tsx' code={ SourceBasic } />

Complete Modal

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 } />

Drawer

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 } />

Uncontrolled with Trigger

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 } />

Non-Modal Popover

A lightweight popover without ScrollLock or backdrop, suitable for non-blocking UI elements:

<Source language='tsx' code={ SourcePopover } />

Composition

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.

Slot System

Overlay passes props to children through the slot system. Children with slot assignments automatically receive the appropriate props:

SlotPurposeProps ProvidedRequired
triggerElement that opens/closes the overlaytriggerProps from React Aria (requires a pressable component)No
backdropVisual backdrop behind contentoverlayProps from React AriaNo
contentMain overlay content containeroverlayProps from React AriaYes

Note: The trigger slot must be filled with a component that consumes React Aria press events (for example @bento/button or any primitive built on @bento/pressable). Passing a raw DOM element (e.g. Container as="button") leaves the onPress handler on the native element, which React ignores and will log warnings.

Component Structure

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)

Controlled vs Uncontrolled

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>

React Aria Integration

Overlay integrates React Aria's overlay hooks to provide accessible behavior:

  • useOverlayTriggerState: Manages controlled/uncontrolled state
  • useOverlayTrigger: Provides trigger and overlay props
  • useModalOverlay: For modal semantics (via composed children)
  • useOverlay: For dismissal behavior (via composed children)

The component passes React Aria hook return values to children via slots, allowing consumers to manually compose primitives while maintaining proper accessibility.

Accessibility

Overlay is designed with accessibility as a foundation:

State Management

  • Controlled and uncontrolled state patterns via React Aria
  • Proper trigger-overlay relationship through ARIA attributes
  • State communicated to children via slots

Focus Management

  • Delegated to FocusLock primitive when composed
  • Focus trapping for modal patterns
  • Focus restoration on close
  • Initial focus control

Keyboard Support

  • ESC key handling via React Aria overlayProps
  • Tab navigation contained within FocusLock
  • Trigger activation via Space/Enter

Screen Reader Support

  • Proper ARIA attributes from React Aria hooks
  • Dismiss components for linear navigation
  • Modal semantics when appropriate

Data Attributes

Overlay applies the following data attribute to help with styling and testing:

AttributeDescriptionExample Values
data-stateCurrent 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:

  • @bento/portal: Renders content outside normal DOM hierarchy
  • @bento/focus-lock: Traps focus within overlay boundaries
  • @bento/scroll-lock: Prevents background scrolling
  • @bento/dismiss: Accessible dismiss controls for screen readers
  • @bento/container: Base primitive for polymorphic rendering
  • @bento/button: Accessible button component for triggers and actions
  • @bento/text: Typography component for overlay content

Server-Side Rendering

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.

Browser Support

Overlay supports all modern browsers through React Aria's cross-browser compatibility layer. The component handles platform-specific behavior transparently.

Customization

Slots

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 useOverlayTrigger
  • backdrop: Receives overlay props for backdrop interactions
  • content: Receives overlay props for content container

See the @bento/slots package for more information on how to use the slot and slots properties.

Styling

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;
}

Best Practices

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.

Performance

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.

Keywords

accessibility

FAQs

Package last updated on 18 Dec 2025

Did you know?

Socket

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.

Install

Related posts