Skip to content

Sheet

A modal panel that slides in from an edge (also called Drawer). Fades instead under reduced motion.

  • Free core, MIT
  • Version 2.0.0-rc.1
  • APG pattern: Dialog (modal), side sheet

Examples

These are the real React components. Use them with a mouse, touch or keyboard, and switch the theme and density for every example at once.

Default

Show the code

Default, code

const Body = () => (
  <>
    <TextField label="Customer" />
    <Switch>Overdue only</Switch>
  </>
);

const Footer = () => <><Button variant="outline" slot="close">Cancel</Button><Button slot="close">Apply filters</Button></>;

<SheetTrigger><Button variant="outline">Filters</Button><Sheet {...args} description="Narrow the list of invoices." footer={<Footer />}><Body /></Sheet></SheetTrigger>

Open

Show the code

Open, code

const Body = () => (
  <>
    <TextField label="Customer" />
    <Switch>Overdue only</Switch>
  </>
);

const Footer = () => <><Button variant="outline" slot="close">Cancel</Button><Button slot="close">Apply filters</Button></>;

<SheetTrigger defaultOpen><Button variant="outline">Filters</Button><Sheet {...args} description="Narrow the list of invoices." footer={<Footer />}><Body /></Sheet></SheetTrigger>

Start

Show the code

Start, code

<SheetTrigger defaultOpen><Button variant="outline">Menu</Button><Sheet side="start" title="Navigation"><p className="text-body-md">Links go here.</p></Sheet></SheetTrigger>

Bottom

Show the code

Bottom, code

<SheetTrigger defaultOpen><Button variant="outline">Share</Button><Sheet side="bottom" title="Share" footer={<Button slot="close">Done</Button>}><p className="text-body-md">Anyone with the link can view.</p></Sheet></SheetTrigger>

Large

Show the code

Large, code

<SheetTrigger defaultOpen><Button variant="outline">Basket</Button><Sheet size="lg" title="Your basket" description="2 items" footer={<><Button variant="outline" slot="close">Keep shopping</Button><Button slot="close">Check out</Button></>}><p className="text-body-md">Items go here.</p></Sheet></SheetTrigger>

Small

Show the code

Small, code

<SheetTrigger defaultOpen><Button variant="outline">Notifications</Button><Sheet size="sm" title="Notifications"><p className="text-body-md">You are all caught up.</p></Sheet></SheetTrigger>

Tokens

The 15 design tokens Sheet reads, with the value each has in the theme and density chosen above. Change a token and the component follows, in Figma and in code.

Show all 15 tokens
Tokens Sheet reads
TokenValue nowCSS variable
color.border.subtle…--sd-color-border-subtle
color.text.secondary…--sd-color-text-secondary
dialog.bg…--sd-dialog-bg
dialog.fg…--sd-dialog-fg
dialog.padding…--sd-dialog-padding
dialog.radius…--sd-dialog-radius
dialog.scrim…--sd-dialog-scrim
elevation.3…--sd-elevation-3
layer.modal…--sd-layer-modal
spacing.gap.md…--sd-spacing-gap-md
spacing.gap.sm…--sd-spacing-gap-sm
spacing.inset.lg…--sd-spacing-inset-lg
spacing.inset.md…--sd-spacing-inset-md
spacing.stack.md…--sd-spacing-stack-md
spacing.stack.xs…--sd-spacing-stack-xs

Install

The npm package isn’t published yet. When it is, this is the install line; until then, this page runs the same build of the package (from commit fa3abf8).

Install

npm i @superduperui/react @superduperui/tokens

Import

import { Sheet, SheetTrigger } from "@superduperui/react"

Props

Sheet also takes the props of the React Aria component it’s built on.

Sheet props
PropTypeWhat it does
titlerequiredstringRequired: the visible heading and the dialog's name.
descriptionReactNode
childrenReactNode | ((opts: { close: () => void }) => ReactNode)Body, or a render function that receives `close`.
footerReactNodeActions pinned to the bottom of the sheet. Buttons with slot="close" close it.
side'end' | 'start' | 'bottom'Default 'end'end (default; right in left-to-right languages), start, or bottom.
size'sm' | 'md' | 'lg'Default 'md'Width of an end or start sheet: sm 360px, md 448px (default), lg 640px; never wider than the viewport. A bottom sheet spans the width.
isOpenboolean
onOpenChange(isOpen: boolean) => void
classNamestring

When to use it

Use it for

  • Filters, details and edit forms beside a list
  • Navigation on small screens (side start)
  • Share sheets (side bottom)

Use something else for

  • Short confirmations: use AlertDialog
  • Content people need while working on the page: use a non-modal panel

Accessibility

Screen readers announce "Filters, dialog, Narrow the list of invoices".

WCAG 2.2 AAA criteria the component meets in Comfortable density: 1.4.6, 1.4.9, 2.1.3, 2.3.2, 2.4.13, 2.5.5, 2.5.6, 2.3.3.

Compact density meets AA (2.5.8, 24px targets), not AAA.

What your product still has to do

  • Keep the footer actions short

Shared patterns it ships with: 2.4.12 (footer pinned, body scrolls).

This release’s test results

Test results for Sheet in this release
axe-core (WCAG A, AA, AAA and best practice)120 runs across every story, theme, density and width: 0 violations
Rendered text contrast120 text runs: 0 below 7:1, lowest 11.42:1
Target size36 targets: 0 under 44px in Comfortable
Focus appearance (2.4.13)18 focus stops in 3 browser engines: all pass
Keyboard scriptChromium 4 of 4, Firefox 4 of 4, WebKit 4 of 4

Manual passes with VoiceOver and NVDA haven’t been done yet.

Keyboard

Each step is scripted and run in Chromium, Firefox and WebKit.

Sheet keyboard steps
KeyWhat happens
TabTab reaches the trigger
EnterEnter opens the sheet and focus moves inside
TabTab cycles inside: focus never leaves the sheet
EscapeEsc closes it (a second Esc if a tooltip was open) and focus returns to the trigger

In Figma

The Figma component is Sheet, with Side (End, Start, Bottom); Width (Medium, Small, Large). The Figma library isn’t published yet.

Figma to code: Side → side (End = "end", Start = "start", Bottom = "bottom"); Title → title; Description → description when Show description; Content → children; Width → size (Medium = "md", Small = "sm", Large = "lg"); nested Footer → footer; nested Close → (built in).