Overlay
Sheet
A panel that slides in from an edge of the window for a task or detail that belongs beside the page.
Import
import { Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription } from "@booleanpress/ui/sheet"Usage
A sheet is a modal dialog drawn against an edge. Use it for a form or a detail view that should keep the page visible behind it; use a dialog for a short, centred task. SheetTitle names it and SheetDescription describes it.
import { Button } from "@booleanpress/ui/button"
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@booleanpress/ui/sheet"
export function EditConnection() {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="outline">Edit connection</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Edit connection</SheetTitle>
<SheetDescription>Change how this mailer signs in.</SheetDescription>
</SheetHeader>
<SheetFooter>
<SheetClose asChild>
<Button>Save</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
)
}side chooses the edge: right (the default), left, top or bottom. Left and right sheets are three quarters of the window wide, at most 384 px. The sheet is a flex column: give the part that should scroll flex-1 overflow-y-auto, and the header and footer stay in place. showCloseButton={false} removes the × when the footer offers the ways out. Control it with open and onOpenChange; without a trigger, focus returns to the element that had it, or to returnFocusTo.
Examples
Basic
A form in a right-hand sheet, with Save and Cancel in the footer.
Sides
side on each of the four edges.
Long content
A list taller than the window scrolls; the header and footer stay visible.
Without the ×
showCloseButton={false}: the footer and Escape are the ways out.
Accessibility
- Semantics
- A
divwithrole="dialog"andaria-modal="true", named bySheetTitleand described bySheetDescription. The rest of the page is hidden from assistive technology while it is open. - Labels
- Every sheet needs a
SheetTitle; keep it for screen readers withclassName="sr-only"if the design shows none. The × button's name comes from the provider'sclosestring. - Focus
- Focus moves into the sheet when it opens, Tab and Shift+Tab stay inside, and focus returns to the trigger when it closes. Without a trigger it returns to the element that had focus when it opened, or to
returnFocusTowhen that element is gone. - Known limits
- One modal at a time: a sheet can open a select or a popover, not a second sheet or dialog.
Keyboard
| Key | Behaviour |
|---|---|
| Escape | Closes the sheet. |
| Tab | Moves to the next focusable element inside the sheet, wrapping from the last to the first. |
| ShiftTab | Moves to the previous focusable element, wrapping from the first to the last. |
API
Sheet
Renders Radix Sheet.Root and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | Whether it starts open, when it controls itself. | |
modal | boolean | Keep it modal: the rest of the page cannot be reached while it is open. Leave it on. | |
onOpenChange | ((open: boolean) => void) | Called with true or false when it opens or closes. | |
open | boolean | Whether it is open, when you control it. Pair it with onOpenChange. |
SheetTrigger
Renders Radix Sheet.Trigger and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. |
SheetClose
Renders Radix Sheet.Close and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. |
SheetContent
Renders Radix Sheet.Content and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. | |
deferPointerDownOutside | boolean | When true, a 'pointerdown' event outside of the layered element will
wait for the interaction's click event before dispatching, allowing
third-party code to stop propagation of later events and cancel dismissal. | |
forceMount | true | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. | |
onCloseAutoFocus | ((event: Event) => void) | Event handler called when auto-focusing on close. Can be prevented. | |
onEscapeKeyDown | ((event: KeyboardEvent) => void) | Event handler called when the escape key is down. Can be prevented. | |
onFocusOutside | ((event: FocusOutsideEvent) => void) | Event handler called when the focus moves outside of the DismissableLayer.
Can be prevented. | |
onInteractOutside | ((event: FocusOutsideEvent | PointerDownOutsideEvent) => void) | Event handler called when an interaction happens outside the DismissableLayer.
Specifically, when a pointerdown event happens outside or focus moves outside of it.
Can be prevented. | |
onOpenAutoFocus | ((event: Event) => void) | Event handler called when auto-focusing on open. Can be prevented. | |
onPointerDownOutside | ((event: PointerDownOutsideEvent) => void) | Event handler called when the a pointerdown event happens outside of the DismissableLayer.
Can be prevented. | |
returnFocusTo | ReturnFocusTarget | Where focus goes on close when the element that opened the overlay no longer exists — for example after the confirmed action deleted the row it sat in. | |
showCloseButton | boolean | true | Render the × button. |
side | "left" | "right" | "top" | "bottom" | right | The screen edge it slides from. |
SheetHeader
Renders a div and passes it every other prop.
SheetFooter
Renders a div and passes it every other prop.
SheetTitle
Renders Radix Sheet.Title and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. |
SheetDescription
Renders Radix Sheet.Description and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | Render the child element instead, with this part's behaviour and classes merged onto it. |
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="sheet" (Sheet), data-slot="sheet-trigger" (SheetTrigger), data-slot="sheet-close" (SheetClose), data-slot="sheet-content" (SheetContent), data-slot="sheet-header" (SheetHeader), data-slot="sheet-footer" (SheetFooter), data-slot="sheet-title" (SheetTitle), data-slot="sheet-description" (SheetDescription).
Provider strings: close (BooleanUIProvider's strings).
Theming
The panel is a floating surface, like menus and popovers: --popover and --popover-foreground. The left and right sheets are placed with logical edges (start, end), so in a right-to-left page side="right" sits at the left edge; the slide animation still moves along the physical axis.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--background | background |
--foreground | text |
--muted-foreground | text |
--popover | background |
--popover-foreground | text |