Skip to main content

Drawer

Stable

Side panel overlay that slides in from any edge. Uses the same compound API as Dialog. Animation direction follows the side prop. Focus trap and restoration built in.

OverlayCompoundFocus trapVhyxSeal

Interactive example

Click a side button to open that drawer

Import

tsx
import { Drawer } from '@vhyxui/react'

// Same sub-components as Dialog
// Drawer.Trigger, Drawer.Portal, Drawer.Overlay
// Drawer.Content, Drawer.Header, Drawer.Footer
// Drawer.Title, Drawer.Description, Drawer.Close

Sides

All four sides

Sizes

sm, md, lg, full — width for side drawers, height for top/bottom

Props

PropTypeDefaultDescription
openbooleanControlled open state.
onOpenChange(open: boolean) => voidCalled when the open state changes.
side'left' | 'right' | 'top' | 'bottom''right'Which edge the drawer slides in from.
size'sm' | 'md' | 'lg' | 'full''md'Width (left/right) or height (top/bottom) of the panel.
contractPartial<ComponentContract>VhyxSeal contract override.

Accessibility

  • role="dialog", aria-modal="true", aria-labelledby pointing to Drawer.Title.
  • Drawer.Title is required — a development warning is logged if absent.
  • Focus trap and Escape-to-close — identical behavior to Dialog.
  • Focus returns to the exact trigger element on close.

Keyboard navigation

KeyAction
EscapeClose the drawer and return focus to the trigger.
TabCycle through focusable elements inside the drawer.
Shift + TabReverse focus cycle within the drawer.

Agent contract

Default VhyxSeal contract shipped with every Drawer.

Default contract
{
  "type": "navigation",
  "intent": "open-drawer",
  "description": "Opens a slide-in panel from a screen edge for navigation or contextual content",
  "requires": [],
  "requiredPermissions": [],
  "consequence": "Renders a side panel overlay — underlying page remains accessible",
  "affects": [
    "view"
  ],
  "reversible": true,
  "safetyLevel": "low",
  "requiresConfirmation": false,
  "destructive": false,
  "contractVersion": "0.0.1",
  "fingerprint": "vhyxs_777f4680"
}

Theming

Override these CSS tokens to theme Drawer.

--vhyx-z-modalZ-index (400)
--vhyx-color-surfacePanel background
--vhyx-shadow-2xlPanel shadow
--vhyx-duration-slowSlide animation duration
--vhyx-easing-decelerateEntry easing

Examples

Navigation drawer (left)

Slide-in nav menu

Mobile filter panel (bottom)

tsx
<Drawer side="bottom" size="lg">
  <Drawer.Trigger asChild>
    <Button>Filters</Button>
  </Drawer.Trigger>
  <Drawer.Portal>
    <Drawer.Overlay />
    <Drawer.Content>
      <Drawer.Header>
        <Drawer.Title>Filter results</Drawer.Title>
      </Drawer.Header>
      {/* filter controls */}
      <Drawer.Footer>
        <Button style={{ width: '100%' }}>Apply filters</Button>
      </Drawer.Footer>
    </Drawer.Content>
  </Drawer.Portal>
</Drawer>