Components / Overlays
Sheet
A Dialog docked to an edge of the screen: a drawer from the bottom, or a full-height panel at the inline end. It behaves exactly like a Dialog (focus, Escape, backdrop, labels) and slides in from its side.
When to useLink to "When to use"
- Settings or filters on a phone: a bottom sheet keeps them within thumb reach.
- An inspector or detail panel beside the content:
side="end". - A navigation drawer on small screens:
side="start"(AppShell uses one).
Use something else when:
- it is a short decision or form in the middle of the page: Dialog (which turns into a bottom sheet on its own in narrow containers)
- it should stay open while the person works on the page: a layout panel, not an overlay
UsageLink to "Usage"
tsx
import { Sheet, Switch } from "@arshad-shah/cynosure";
<Sheet open={open} onOpenChange={setOpen} side="end" title="Settings">
<Switch label="Compact rows" />
</Sheet>PropsLink to "Props"
| Prop | What it does | Type | Default |
|---|---|---|---|
titleRequired | Heading of the dialog; also its accessible name. | ReactNode | |
side | Edge it docks to: the bottom (full width), the inline end (full height; left in right-to-left text) or the inline start (full height; a navigation drawer; right in right-to-left text). | "bottom" | "start" | "end" | |
open | Whether the dialog is open, when you control it. | boolean | |
defaultOpen | Open on first render when uncontrolled. | boolean | |
onOpenChange | Called with false when the dialog closes itself: Escape, the backdrop or the close button. | ((open: boolean) => void) | |
description | One or two sentences under the title; also its accessible description. | ReactNode | |
actions | Buttons along the bottom, outside the scrolling content (Cancel first, then the main action). | ReactNode | |
size | Width preset (the panel never grows wider than its container). | Size | |
dismissible | Escape, the backdrop and the close button close it (default). false leaves only your actions. | boolean | |
keepMounted | Keep the content in the DOM while the dialog is closed. By default a closed dialog renders nothing inside it: the content mounts when it opens and unmounts once the closing transition has ended, so every opening starts fresh. Set it for content whose state must survive closing (a half-filled form) or that is expensive to rebuild. Default false. | boolean | false |
labels | Replace the built-in English text: the close button's name. | Partial<DialogLabels> | |
className | Added to the panel, for layout. | string | |
style | Layout only, applied to the panel. Restyle through --cy-dialog-* tokens. | CSSProperties | |
children | The content; it scrolls when it is taller than the dialog. | ReactNode |
Generated from the type definitions in @arshad-shah/cynosure 0.5.0.
Behaviour and accessibilityLink to "Behaviour and accessibility"
| Input | Result |
|---|---|
| Escape | Closes the topmost layer, then the sheet |
| Tab | Moves through the sheet only; the page behind is inert |
| Tap or click on the backdrop | Closes it |
- Sides:
bottomis full width and up to 85% of the height;endis full height and docks to the right (left in right-to-left text);startis full height and docks to the left (right in right-to-left text). - Size:
sizesets the width of anendorstartsheet. - Mounting: the content is in the DOM only while the sheet is open, and is removed once it has slid out, so every opening starts fresh.
keepMountedkeeps it while closed, for a drawer whose scroll position or expanded sections should survive. - Everything else (focus, roles, shadow DOM, no writes to
<body>) is the same as Dialog.
TouchLink to "Touch"
Bottom-sheet actions stay above the home indicator (safe-area-inset-bottom), and a tap on the backdrop closes it.
ThemingLink to "Theming"
Tokens: --cy-sheet-radius, --cy-sheet-width-{sm,md,lg} and --cy-sheet-max-height, plus the Dialog tokens for padding and scrim.
ts
createTheme({ components: { sheet: { widthMd: "440px", maxHeight: "90%" } } });RelatedLink to "Related"
These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.