Manual UI Templates Sheet

Sheet

elements man ui/templates/sheet

A dialog that slides in from an edge of the screen, for content that complements the page.

Example
import { Sheet, SheetBody, SheetFooter, SheetClose } from "@elements/ui/sheet"; import { Button } from "@elements/ui/button"; <Sheet side="right" title="Edit profile" description="Make changes, then save."> <Button slot="trigger">Edit profile</Button> <SheetBody> <input value={form.name}> </SheetBody> <SheetFooter> <Button variant="primary" onclick={() => save(form)}>Save changes</Button> <SheetClose><Button>Close</Button></SheetClose> </SheetFooter> </Sheet> <!-- controlled: open is two-way --> <Sheet open={state.filters} side="left" title="Filters">...</Sheet>

Parts

Part What it is
Sheet The root: owns open, renders the trigger slot and, while open, the <dialog> overlay, the backdrop and the docked panel.
SheetHeader Stacks a title and description.
SheetTitle An <h2>; names the sheet (aria-labelledby).
SheetDescription A <p>; describes the sheet (aria-describedby).
SheetBody The content between header and footer; it scrolls when the content is taller than the sheet, so the header and footer stay in place.
SheetFooter Actions pinned to the bottom, stacked full width.
SheetClose Wraps any element; clicking it closes this sheet.

Attributes

Sheet

Attribute Type Default Description
open boolean (two-way) false Whether the sheet is open. Bind it to control it; the sheet writes false back when it closes itself. Omit it and the trigger slot opens it.
side "top" | "right" | "bottom" | "left" | "start" | "end" "right" The edge the sheet docks to and slides from. start and end follow the writing direction (end is the left edge under rtl).
title string "" Renders a SheetTitle in a header and names the sheet.
description string "" Renders a SheetDescription under the title.
label string "" aria-label for a sheet with no visible title.
modal boolean | "trap-focus" true true: backdrop, inert page, focus trap, scroll lock. "trap-focus": focus is trapped but there is no backdrop or lock, and the page takes clicks. false: the page stays usable.
dismissOnEscape boolean true Escape closes the sheet.
dismissOnOutside boolean true A press outside the panel closes the sheet.
closeButton boolean true Shows the X button in the corner.
initialFocus DialogFocus "" CSS selector of the element to focus on open, or a function of the interaction type (keyboard, mouse, touch, pen) that returns an element, a selector, true for the default or false to leave focus. Default: [autofocus], else the first focusable element that is not a link, else the panel.
returnFocus boolean true Return focus to the trigger (or whatever had focus) when the sheet closes.
finalFocus DialogFocus "" CSS selector of the element to focus on close, in place of the trigger, or a function of the interaction type that returns an element, a selector, true for the trigger or false to leave focus.
size "sm" | "md" | "lg" | "xl" | "full" "md" Max width of a side sheet: 20, 24, 36, 48rem or the full viewport. A side sheet is 75% of the viewport up to that width; top and bottom sheets span the width.
scroll "inside" | "outside" "inside" inside: the sheet fits its edge and SheetBody scrolls. outside: the sheet grows with its content and the overlay scrolls it as one (an outside scroll dialog); a side sheet is at least the viewport's height.
class string "" Extra classes on the panel.
onOpenChangeComplete (open: boolean) => void () => {} Called after the enter animation (true) or once the sheet has left the page after its exit (false).
onOpenChange (open: boolean, reason?: DialogChangeReason, details?: DialogChangeDetails) => void () => {} Called when the sheet opens or closes itself, with a reason: trigger-press, outside-press, escape-key, close-press, focus-out, close-watcher (a platform close request such as Android back), or none when the browser closed it. Not called for changes the caller makes. The third argument is the event details: { reason, event (the DOM event behind the change, or null), trigger (the trigger element on trigger-press) }.
onInteractOutside (e: Event) => void () => {} Called before a press or focus outside dismisses it; e.preventDefault() keeps it open.
onOpenAutoFocus (e: Event) => void () => {} Called before focus moves in on open; e.preventDefault() leaves focus to the handler.
onCloseAutoFocus (e: Event) => void () => {} Called before focus returns on close; e.preventDefault() leaves focus to the handler.
onEscapeKeyDown (e: KeyboardEvent) => void () => {} Called on Escape before closing; e.preventDefault() keeps it open, and e.allowPropagation() lets the Escape reach the page's own key handlers too.
onPointerDownOutside (e: PointerEvent) => void () => {} Called on a press outside before closing; e.preventDefault() keeps it open.

SheetHeader, SheetTitle, SheetDescription, SheetBody, SheetFooter

Attribute Type Default Description
class string "" Extra classes.

Slots

Slot Content
trigger The element that opens the sheet. It gets aria-haspopup, aria-expanded, aria-controls and data-state.
default The sheet's content, below the header.

Keyboard

Keys Action
Space / Enter On the trigger: opens the sheet.
Tab Moves to the next focusable element inside; wraps from the last to the first.
Shift + Tab Moves to the previous focusable element; wraps from the first to the last.
Escape Closes the sheet (unless dismissOnEscape is false or onEscapeKeyDown prevents it).

Data attributes

Attribute Values On Description
data-open present .dialog-overlay, .sheet-backdrop, .sheet While open; the same moment as data-state="open".
data-closed, data-ending-style present .dialog-overlay, .sheet-backdrop, .sheet During the exit animation; the same moment as data-state="closed".
data-starting-style present .dialog-overlay, .sheet-backdrop, .sheet For the first frame after the overlay mounts, so a CSS transition can start from it.
data-popup-open present trigger While open; the same moment as the trigger's data-state="open".
data-state "open" | "closed" trigger, .dialog-overlay, .sheet-backdrop, .sheet closed during the exit animation.
data-side "top" | "right" | "bottom" | "left" | "start" | "end" .sheet
data-modal "true" | "false" .dialog-overlay
data-scroll-locked present <body> While a modal sheet is open.
data-sheet-scroll-stop present .sheet-body The body overflows and is a Tab stop (tabindex 0), a region named after the title.
data-nested present .sheet The sheet sits inside another dialog panel.
data-nested-dialog-open present .sheet A dialog opened from inside this one is open. --nested-dialogs holds the count.

Accessibility

  • The overlay is a native <dialog> opened with showModal(): role dialog, the top layer, and an inert page behind it.
  • aria-modal="true", aria-labelledby (the title) and aria-describedby (the description) are set on it.
  • Focus moves into the sheet on open, is trapped while modal, and returns to the trigger on close.
  • The close button is an icon button with aria-label="Close".

See also