Usage
import { ResponsiveSheet } from "@voila.dev/ui/responsive-sheet";<ResponsiveSheet.Root>
<ResponsiveSheet.Trigger render={<Button variant="outline" />}>Open</ResponsiveSheet.Trigger>
<ResponsiveSheet.Content size="xl">
<ResponsiveSheet.Header>
<ResponsiveSheet.Title>Email details</ResponsiveSheet.Title>
</ResponsiveSheet.Header>
<ResponsiveSheet.Body>…</ResponsiveSheet.Body>
</ResponsiveSheet.Content>
</ResponsiveSheet.Root>A Sheet on desktop and a bottom Drawer on small screens. Reach for this over plain Sheet for detail panels, which are the ones that hurt most on a phone: a side panel on a narrow viewport is either a sliver or a modal pretending not to be one.
Recipes
size sets the desktop panel width; the mobile drawer is always full-width,
because a partial bottom sheet on a phone wastes the only dimension it has.
As with ResponsiveDialog, the root holds the open state
so crossing the breakpoint does not close the panel, and autoFocus={false}
keeps the keyboard down when the first field is a text input.
API
ResponsiveSheet.Root
| Prop | Type | Default | |
|---|---|---|---|
children | ReactNode | — | The trigger and the content. |
defaultOpen | boolean | false | Whether it starts open, when uncontrolled. |
onOpenChange | ((open: boolean) => void) | — | Called when the overlay opens or closes, on either surface. |
open | boolean | — | Controlled open state. The root owns it so it survives crossing the breakpoint. |
Plus the DOM props of the element it renders. Source: responsive-sheet/components/responsive-sheet-root.tsx.
ResponsiveSheet.Body
Plus every <div> prop. Source: responsive-sheet/components/responsive-sheet-body.tsx.
ResponsiveSheet.Close
| Prop | Type | Default | |
|---|---|---|---|
render | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Element form only — the drawer half clones it, so render functions are unsupported. |
Plus the DOM props of the element it renders. Source: responsive-sheet/components/responsive-sheet-close.tsx.
ResponsiveSheet.Content
| Prop | Type | Default | |
|---|---|---|---|
autoFocus | boolean | true | Whether opening moves focus into the content (the default). Pass false
when the first field is a text input you don't want to focus on open —
on a phone that focus opens the keyboard over the content you just asked to
see. The content stays reachable by tab either way. |
children | ReactNode | — | Header, body and footer parts. |
className | string | — | Classes for the panel on both surfaces. |
closeButtonLabel | string | "Close" | Accessible name for that X. This package ships no translations. |
overlayClassName | string | — | Classes for the backdrop behind the panel. className styles the panel itself. |
showCloseButton | boolean | true | Draws the X in the corner. |
size | SheetContentSize | "default" | Desktop panel width — the mobile drawer is always full-width. |
Plus the DOM props of the element it renders. Source: responsive-sheet/components/responsive-sheet-content.tsx.
ResponsiveSheet.Description
| Prop | Type | Default | |
|---|---|---|---|
asChild | boolean | — |
Plus the DOM props of the element it renders. Source: responsive-sheet/components/responsive-sheet-description.tsx.
ResponsiveSheet.Footer
| Prop | Type | Default | |
|---|---|---|---|
closeLabel | string | — | Renders an outline close button after children. |
Plus every <div> prop. Source: responsive-sheet/components/responsive-sheet-footer.tsx.
ResponsiveSheet.Header
Plus every <div> prop. Source: responsive-sheet/components/responsive-sheet-header.tsx.
ResponsiveSheet.Title
| Prop | Type | Default | |
|---|---|---|---|
asChild | boolean | — |
Plus the DOM props of the element it renders. Source: responsive-sheet/components/responsive-sheet-title.tsx.
ResponsiveSheet.Trigger
| Prop | Type | Default | |
|---|---|---|---|
render | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Element form only — the drawer half clones it, so render functions are unsupported. |
Plus the DOM props of the element it renders. Source: responsive-sheet/components/responsive-sheet-trigger.tsx.