Sheet
Opens a focused task from a screen edge. Native dialog with platform focus handling and backdrop.
Preview
In action
When to use
Use it for
- Filters, settings, or a detail view that slides in beside the page.
- side="left" for navigation on phones.
Not for
- Short decisions; use Dialog.
- Content that should stay open while the page is used; the sheet is modal.
Install
Three ways in. They share one source, so the pixels match whichever you pick.
1. Import the package
npm install @noorddev/vlak-react
// once, next to your app's root
import "@noorddev/vlak-react/css";
import { Button, Sheet, SheetBody, SheetTitle } from "@noorddev/vlak-react";Precompiled React and one stylesheet. No compiler to configure. Per-component imports work too: @noorddev/vlak-react/components/sheet.
2. Vendor the source
npx @noorddev/vlak-cli add sheet
The StyleX leaf lands in components/vlak/ with its dependencies, for your own compiler to own. See StyleX.
3. Through shadcn
npx shadcn add https://vlak.dev/r/sheet.json
The same registry item, installed by shadcn's CLI.
CSS only
<link rel="stylesheet" href="node_modules/@noorddev/vlak/css/vlak.css" />
No React. Link vlak.css and use the markup and classes below.
React
import { useState } from "react";
import { Button, Sheet, SheetBody, SheetTitle } from "@noorddev/vlak-react";
const [open, setOpen] = useState(false);
<Button variant="ghost" onClick={() => setOpen(true)}>Filters</Button>
<Sheet open={open} onClose={() => setOpen(false)} side="right" closeLabel="Close">
<SheetTitle>Filters</SheetTitle>
<SheetBody>Everything narrows from here.</SheetBody>
</Sheet>Props
Sheet
A native <dialog> at the screen edge. The platform provides the focus trap, Escape, and the backdrop; the title names it.
| Prop | Type | Default | Description |
|---|---|---|---|
openrequired | boolean | ||
onClose | () => void | ||
dismissable | boolean | Escape (and any other platform close request) asks the parent to close. Off, the dialog must be answered; maps to closedby="none". | |
lightDismiss | boolean | A click on the backdrop closes too; maps to closedby="any". | |
closeLabel | string | Renders a labelled close button in the top corner. | |
side | "left" | "right" | "right" |
Also accepts Omit<DialogHTMLAttributes<HTMLDialogElement>, "open" | "onClose">.
SheetBody
Also accepts HTMLAttributes<HTMLParagraphElement>.
SheetTitle
| Prop | Type | Default | Description |
|---|---|---|---|
as | "h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span" | "div" | "h2" |
Also accepts HTMLAttributes<HTMLHeadingElement>.
Keyboard
| Keys | Does |
|---|---|
| Escape | Calls onClose (when dismissable, the default) |
| Tab, Shift + Tab | Cycles focus inside the sheet |
Accessibility
- A native modal <dialog> docked to an edge: the platform traps focus and provides the backdrop.
- SheetTitle names it through aria-labelledby; SheetBody describes it. Focus moves in on open and returns on close.
- closeLabel renders a labelled close button; lightDismiss closes on a backdrop click. The ref is forwarded to the <dialog>.
Markup
<dialog class="rs-sheet" aria-labelledby="filters-title" open><button class="rs-sheet-close" type="button" aria-label="Close">×</button><h2 class="rs-sheet-title" id="filters-title">Filters</h2><p class="rs-sheet-body">Everything narrows from here.</p></dialog>