Sheet
A modal panel that slides in from an edge of the viewport, for filters, details and secondary tasks that keep the page in context.
Preview
Installation
pnpm add @syntara/react @syntara/tokensimport { Sheet } from '@syntara/react';Usage
import { Button, DialogTrigger, Sheet } from '@syntara/react';
export function Filters() {
return (
<DialogTrigger>
<Button variant="outline">Filters</Button>
<Sheet side="end" title="Filters" footer={({ close }) => <Button onPress={close}>Show results</Button>}>
{/* fields */}
</Sheet>
</DialogTrigger>
);
}Examples
Sides
start, end, top and bottom. start and end are logical and swap in right-to-left layouts.
Accessibility
| Keys | Action |
|---|---|
| EnterorSpace | On the trigger: opens the sheet and moves focus into it. |
| TaborShiftTab | Moves between focusable elements; focus is trapped inside the sheet. |
| Escape | Closes the sheet and returns focus to the trigger. |
- A modal dialog (role="dialog") named by its title; the page behind is inert while it is open.
- Overlays render in a portal on <body>, outside any ThemeScope. When it opens, the overlay looks up data-syntara-theme, data-syntara-scheme, data-syntara-density, dir and lang — each on the nearest ancestor that has it — starting from its trigger (or from where the component is rendered, when controlled), and copies them onto its own root — so it uses the same tenant tokens and direction as the page region it came from, and nested overlays inherit from their parent overlay.
- Right-to-left: give the ThemeScope a locale (e.g. locale="ar-AE"), which sets dir and wraps React Aria's I18nProvider, so arrow keys and start/end placement flip as well as the layout.
- The backdrop blurs the page lightly and dims it with backdrop-filter: brightness(0.6), so it recedes in light and dark schemes alike. The panel is glass (--syntara-glass-bg + backdrop blur); only text.default and text.subtle sit directly on it, the two roles the theme engine solves to 4.5:1 over any backdrop.
- Motion: the panel slides in from its side (start/end follow the reading direction) and leaves faster than it came. With prefers-reduced-motion it appears without moving.
Guidelines
Do
- Use end for detail and filter panels, bottom for short mobile actions.
- Keep the primary action in the footer so it stays visible while the body scrolls.
Don’t
- Don't use a sheet for navigation that should stay visible — use a persistent sidebar.
- Don't stack sheets.
API reference
Sheet
sidestartenddefaulttopbottom
Edge the panel is attached to. end is the right edge in LTR and the left edge in RTL.
titleRequiredReactNodeHeading; also the panel's accessible name.
descriptionReactNodeSupporting text under the title.
childrenReactNode | (({ close }) => ReactNode)Panel content; scrolls independently of the header and footer.
footerReactNode | (({ close }) => ReactNode)Actions pinned to the bottom of the panel.
isDismissablebooleanWhether clicking the backdrop closes the sheet.
Default
trueisKeyboardDismissDisabledbooleanWhether Escape is ignored.
Default
falseisOpen / defaultOpen / onOpenChangeboolean / boolean / (isOpen: boolean) => voidOpen state when not inside a DialogTrigger.
className / stylestring / CSSPropertiesApplied to the panel, e.g. to change its width.
Tokens
The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.
- Colour4
text.defaultsurface.raisedtext.subtleborder.subtle- Type9
font.bodyfont.size.mdline-height.normalfont.headingfont.size.lgfont.weight.semiboldline-height.snugfont.heading-trackingfont.size.sm- Space and size7
space.2space.16space.4card-insetspace.1control-heightfield-gap- Shape1
radius.container- Depth4
glass.blurshadow.overlayglass.opacityhairline- Motion4
motion.duration.normalmotion.easing-outmotion.easingmotion.duration.slow- Other2
sheenrim