Sheet
A sheet is a modal panel that slides in from an edge of the screen. It is also called a drawer or side panel.
<tk-button onclick="document.getElementById('sheet').show()">Show filters</tk-button>
<tk-sheet id="sheet" heading="Filters" side="right">
<tk-checkbox>Unread</tk-checkbox>
<tk-checkbox>Starred</tk-checkbox>
<tk-button slot="footer" onclick="this.closest('tk-sheet').close()">Clear</tk-button>
<tk-button slot="footer" variant="primary" onclick="this.closest('tk-sheet').close()">Apply</tk-button>
</tk-sheet>Anatomy
| Part | What it is |
|---|---|
| heading | heading: the title and accessible name, required |
| close button | built in, top right |
| body | the default slot; it scrolls |
| footer | the footer slot: your buttons, right-aligned; hidden when empty |
| backdrop | dims the page and blocks it |
dialog part |
the panel |
Sides
<tk-button onclick="document.getElementById('filters').show()">Show filters</tk-button>
<tk-sheet id="filters" heading="Filters" side="right">
<tk-checkbox>Unread</tk-checkbox>
<tk-checkbox>Starred</tk-checkbox>
<tk-button slot="footer" onclick="this.closest('tk-sheet').close()">Clear</tk-button>
<tk-button slot="footer" variant="primary" onclick="this.closest('tk-sheet').close()">Apply</tk-button>
</tk-sheet>side |
Shape |
|---|---|
right (default) |
full height, 440px wide |
left |
full height, 440px wide |
top |
full width, as tall as its content |
bottom |
full width, as tall as its content |
- The panel slides in from its side and back out when it closes.
- A side sheet narrows to fit the viewport with
space-16(16px) to spare. A top or bottom sheet grows up to the viewport height minus 16px, then its body scrolls. - To change a side sheet's width, set
--tk-sheet-size. There is nosizeattribute. - Long content scrolls in the body while the heading and footer stay put. The content fades at an edge while there's more beyond it.
Opening and closing
<tk-button onclick="document.getElementById('details').show()">View details</tk-button>
<tk-sheet id="details" heading="Order 1024" side="right">
<p>Shipped on 12 March to Ada Lovelace, London.</p>
</tk-sheet>show()opens the sheet, always as a modal.close(value)closes it, andreturnValueholds the value in yourcloselistener. Focus goes back to the element that opened it.- A sheet closes the same ways as a
Dialog :Esc, the close button, a backdrop click, or your buttons. Closing never saves anything. - A sheet that holds a
<form>doesn't close on a backdrop click, so a stray click can't lose the work.Escand the close button still close it. - To ask before losing unsaved changes, listen for
cancel:Escand a backdrop click fire it first, andpreventDefault()keeps the sheet open. Then open a "Discard changes?"confirm dialog over the sheet. persistentturns offEscand the backdrop. The close button and your buttons still work. Keep it for a task people must finish.
When to use
- Use a sheet for a supporting panel or task that needs room: filters, item details, settings, a longer form, navigation on a narrow screen.
- Use a
Dialog for a short task or decision in the middle of the screen. - Use a
Popover for something light next to its trigger. To pick a value, useSelect orCombobox . - Use a
Sidebar for navigation that stays on screen. On narrow screens, put the same navigation in a sheet. - A sheet blocks the page. Never open one when a page loads, or for information nobody can act on.
Content
- Heading: name the panel or the task: "Filters", "Edit profile", "Order 1024".
- Footer buttons name the action: "Apply", "Save changes". One
primary, on the right. - Use sentence case.
More in
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
| Use a sheet for filters or details that need room | Use one for a hint or a quick pick; use a popover or select |
| Keep the close button | Hide it and rely on Esc alone |
Ask "Discard changes?" through cancel |
Turn on persistent to protect a form |
| Open a sheet when someone asks for it | Open one when the page loads |
Related
Dialog : the same modal, centered.Sidebar : navigation that stays on screen; a sheet holds it on narrow screens.Popover : a light panel that doesn't block the page.Button : the footer actions.
API
Attributes
| Attribute | Type | Default | What it does |
|---|---|---|---|
heading |
string | none | the title and accessible name; required |
side |
top | right | bottom | left |
right |
the edge the sheet sits on and slides from |
persistent |
boolean | false |
Esc and backdrop clicks don't close it |
backdrop-blur |
boolean | false |
blurs the page behind the backdrop |
backdrop-blur is off by default because blur costs performance. Where the browser can't
blur, the backdrop just dims.
Slots
| Slot | Content |
|---|---|
| default | the body; put autofocus on the first field of a form |
footer |
the buttons, usually tk-buttons |
Methods and properties
| Name | What it does |
|---|---|
show() |
opens the sheet as a modal |
close(returnValue?) |
closes it; without a value, it closes as a dismissal |
returnValue |
the value of the last close; "" after a dismissal |
open |
read-only, true while open; the open attribute mirrors it but doesn't open anything |
Events
| Event | When |
|---|---|
close |
after the sheet closes, by any path; read returnValue |
cancel |
Esc or a backdrop click asks to close; preventDefault() keeps it open |
Both fire on the element and don't bubble, so listen on the sheet itself.
CSS
::part(dialog): the panel.--tk-sheet-size: the width of aleftorrightsheet. Defaultmin(440px, 100vw - 16px).
Tokens
| Part | Tokens |
|---|---|
| backdrop | surface/backdrop; with backdrop-blur, also blur-backdrop (8px) |
| panel | surface/raised, shadow-3, radius-20 on the corners away from the edge; in high contrast, a 1px border/default |
| heading | text/default, Heading Medium (20/24) |
| body | text/default, Body Medium (16/24) |
| spacing | space-16 around the regions, space-8 between buttons |
| slide | duration-200, ease-emphasized |
| buttons |
The backdrop is darker in dark and high contrast. Values per theme:
Accessibility
Built in:
- A native modal
<dialog>withrole="dialog", named by the heading. The page behind can't be clicked, reached with Tab, or read by screen readers. - Focus moves in when it opens, stays inside, and returns to the opener when it closes.
- First focus goes to the element with
autofocus, otherwise the heading. - The page doesn't scroll while a sheet is open.
- With reduced motion, the sheet appears and closes without sliding.
Your part:
- Put
autofocuson the first field of a form. - If the opener is gone after closing, move focus yourself in the
closelistener. - Guard unsaved work with
canceland a confirm, not withpersistent.
| Key | Action |
|---|---|
Esc |
closes the top layer: an open menu or select inside the sheet first, then the sheet; not with persistent |
Tab / Shift+Tab |
moves through the sheet only |