Actions
Sheet
A full-height side panel on a native dialog for details, filters or navigation.
| Class name | Type | Description |
|---|---|---|
sheetplf:sheet | Component | A Modal dialog as a panel on the end side |
sheet-headerplf:sheet-header | Part | Title row with the close button |
sheet-titleplf:sheet-title | Part | The panel's heading |
sheet-descriptionplf:sheet-description | Part | Muted text under the title |
sheet-closeplf:sheet-close | Part | The close button, with modal-close |
sheet-iconplf:sheet-icon | Part | Your own SVG, in place of the drawn x; an icon class there doesn't need it |
sheet-bodyplf:sheet-body | Part | The scrolling content |
sheet-footerplf:sheet-footer | Part | The row of actions at the end |
sheet-handleplf:sheet-handle | Part | The bottom sheet's decorative handle |
sheet-startplf:sheet-start | Placement | On the start side |
sheet-bottomplf:sheet-bottom | Placement | From the bottom edge; see Drawer |
<button class="btn btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-default">Open sheet</button>
<dialog class="modal sheet" data-plf-modal id="sheet-default" aria-describedby="sheet-default-description">
<header class="sheet-header">
<div>
<h2 class="sheet-title">Project details</h2>
<p class="sheet-description" id="sheet-default-description">A little more context for the work ahead.</p>
</div>
<button class="modal-close sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="sheet-body">
<p>Owner: Jordan Rivera. Stage: In review.</p>
</div>
<footer class="sheet-footer">
<button class="btn btn-outline" data-plf-trigger="modal:close">Close</button>
</footer>
</dialog><button class="plf:btn plf:btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-default">Open sheet</button>
<dialog class="plf:modal plf:sheet" data-plf-modal id="sheet-default" aria-describedby="sheet-default-description">
<header class="plf:sheet-header">
<div>
<h2 class="plf:sheet-title">Project details</h2>
<p class="plf:sheet-description" id="sheet-default-description">A little more context for the work ahead.</p>
</div>
<button class="plf:modal-close plf:sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="plf:sheet-body">
<p>Owner: Jordan Rivera. Stage: In review.</p>
</div>
<footer class="plf:sheet-footer">
<button class="plf:btn plf:btn-outline" data-plf-trigger="modal:close">Close</button>
</footer>
</dialog>'use client';
import { useState } from 'react';
import { Button, Sheet, SheetBody, SheetClose, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from '@pelatform/react';
export function Example() {
const [open, setOpen] = useState(false);
return (
<>
<Button variant="outline" onClick={() => setOpen(true)}>Open sheet</Button>
<Sheet open={open} onOpenChange={setOpen}>
<SheetHeader>
<div>
<SheetTitle>Project details</SheetTitle>
<SheetDescription>A little more context for the work ahead.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<p>Owner: Jordan Rivera. Stage: In review.</p>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setOpen(false)}>Close</Button>
</SheetFooter>
</Sheet>
</>
);
}'use client';
import { useState } from 'react';
import { Button, Sheet, SheetBody, SheetClose, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from '@pelatform/react/prefixed';
export function Example() {
const [open, setOpen] = useState(false);
return (
<>
<Button variant="outline" onClick={() => setOpen(true)}>Open sheet</Button>
<Sheet open={open} onOpenChange={setOpen}>
<SheetHeader>
<div>
<SheetTitle>Project details</SheetTitle>
<SheetDescription>A little more context for the work ahead.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<p>Owner: Jordan Rivera. Stage: In review.</p>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setOpen(false)}>Close</Button>
</SheetFooter>
</Sheet>
</>
);
}The sheet’s first heading names it; give the close button an aria-label.
Sides
Sides are logical, so they swap in right-to-left layouts.
<button class="btn btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-start">Start</button>
<button class="btn btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-end">End</button>
<dialog class="modal sheet sheet-start" data-plf-modal id="sheet-start" aria-describedby="sheet-start-description" data-plf-close-on-backdrop>
<header class="sheet-header">
<div>
<h2 class="sheet-title">Start sheet</h2>
<p class="sheet-description" id="sheet-start-description">Jump to a section of this page.</p>
</div>
<button class="modal-close sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="sheet-body">
<nav class="flex flex-col gap-4" aria-label="Section shortcuts">
<a href="#">Cards</a>
<a href="#">Form controls</a>
<a href="#">Usage guide</a>
</nav>
</div>
<footer class="sheet-footer">
<button class="btn btn-outline" data-plf-trigger="modal:close">Close</button>
</footer>
</dialog>
<dialog class="modal sheet" data-plf-modal id="sheet-end" aria-describedby="sheet-end-description">
<header class="sheet-header">
<div>
<h2 class="sheet-title">End sheet</h2>
<p class="sheet-description" id="sheet-end-description">This sheet opens on the end side.</p>
</div>
<button class="modal-close sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="sheet-body">
<p>Owner: Jordan Rivera. Stage: In review.</p>
</div>
<footer class="sheet-footer">
<button class="btn btn-outline" data-plf-trigger="modal:close">Close</button>
</footer>
</dialog><button class="plf:btn plf:btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-start">Start</button>
<button class="plf:btn plf:btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-end">End</button>
<dialog class="plf:modal plf:sheet plf:sheet-start" data-plf-modal id="sheet-start" aria-describedby="sheet-start-description" data-plf-close-on-backdrop>
<header class="plf:sheet-header">
<div>
<h2 class="plf:sheet-title">Start sheet</h2>
<p class="plf:sheet-description" id="sheet-start-description">Jump to a section of this page.</p>
</div>
<button class="plf:modal-close plf:sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="plf:sheet-body">
<nav class="plf:flex plf:flex-col plf:gap-4" aria-label="Section shortcuts">
<a href="#">Cards</a>
<a href="#">Form controls</a>
<a href="#">Usage guide</a>
</nav>
</div>
<footer class="plf:sheet-footer">
<button class="plf:btn plf:btn-outline" data-plf-trigger="modal:close">Close</button>
</footer>
</dialog>
<dialog class="plf:modal plf:sheet" data-plf-modal id="sheet-end" aria-describedby="sheet-end-description">
<header class="plf:sheet-header">
<div>
<h2 class="plf:sheet-title">End sheet</h2>
<p class="plf:sheet-description" id="sheet-end-description">This sheet opens on the end side.</p>
</div>
<button class="plf:modal-close plf:sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="plf:sheet-body">
<p>Owner: Jordan Rivera. Stage: In review.</p>
</div>
<footer class="plf:sheet-footer">
<button class="plf:btn plf:btn-outline" data-plf-trigger="modal:close">Close</button>
</footer>
</dialog>'use client';
import { useState } from 'react';
import { Button, Sheet, SheetBody, SheetClose, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from '@pelatform/react';
export function Example() {
const [start, setStart] = useState(false);
const [end, setEnd] = useState(false);
return (
<>
<Button variant="outline" onClick={() => setStart(true)}>Start</Button>
<Button variant="outline" onClick={() => setEnd(true)}>End</Button>
<Sheet side="start" open={start} onOpenChange={setStart} closeOnBackdrop>
<SheetHeader>
<div>
<SheetTitle>Start sheet</SheetTitle>
<SheetDescription>Jump to a section of this page.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<nav className="flex flex-col gap-4" aria-label="Section shortcuts">
<a href="#">Cards</a>
<a href="#">Form controls</a>
<a href="#">Usage guide</a>
</nav>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setStart(false)}>Close</Button>
</SheetFooter>
</Sheet>
<Sheet open={end} onOpenChange={setEnd}>
<SheetHeader>
<div>
<SheetTitle>End sheet</SheetTitle>
<SheetDescription>This sheet opens on the end side.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<p>Owner: Jordan Rivera. Stage: In review.</p>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setEnd(false)}>Close</Button>
</SheetFooter>
</Sheet>
</>
);
}'use client';
import { useState } from 'react';
import { Button, Sheet, SheetBody, SheetClose, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from '@pelatform/react/prefixed';
export function Example() {
const [start, setStart] = useState(false);
const [end, setEnd] = useState(false);
return (
<>
<Button variant="outline" onClick={() => setStart(true)}>Start</Button>
<Button variant="outline" onClick={() => setEnd(true)}>End</Button>
<Sheet side="start" open={start} onOpenChange={setStart} closeOnBackdrop>
<SheetHeader>
<div>
<SheetTitle>Start sheet</SheetTitle>
<SheetDescription>Jump to a section of this page.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<nav className="plf:flex plf:flex-col plf:gap-4" aria-label="Section shortcuts">
<a href="#">Cards</a>
<a href="#">Form controls</a>
<a href="#">Usage guide</a>
</nav>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setStart(false)}>Close</Button>
</SheetFooter>
</Sheet>
<Sheet open={end} onOpenChange={setEnd}>
<SheetHeader>
<div>
<SheetTitle>End sheet</SheetTitle>
<SheetDescription>This sheet opens on the end side.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<p>Owner: Jordan Rivera. Stage: In review.</p>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setEnd(false)}>Close</Button>
</SheetFooter>
</Sheet>
</>
);
}With a form
Give the form method="dialog", which closes the sheet when it is submitted, and link the footer’s submit button to it with the form attribute.
<button class="btn btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-form">Choose filters</button>
<dialog class="modal sheet" data-plf-modal id="sheet-form" aria-describedby="sheet-form-description">
<header class="sheet-header">
<div>
<h2 class="sheet-title">Project filters</h2>
<p class="sheet-description" id="sheet-form-description">Choose the projects you want to see.</p>
</div>
<button class="modal-close sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="sheet-body">
<form class="flex flex-col gap-4" id="sheet-form-filters" method="dialog">
<div class="field">
<label class="field-label" for="sheet-form-query">Project name</label>
<input class="input" id="sheet-form-query" name="query" type="text" autofocus value="Website">
</div>
<div class="field">
<label class="field-label" for="sheet-form-stage">Stage</label>
<select class="select" id="sheet-form-stage" name="stage" data-plf-select>
<option value="all">All stages</option>
<option value="review">In review</option>
<option value="active">Active</option>
</select>
</div>
<label><input class="checkbox" type="checkbox" name="archived"> Include archived projects</label>
</form>
</div>
<footer class="sheet-footer">
<button class="btn btn-outline" data-plf-trigger="modal:close">Close</button>
<button class="btn btn-primary" type="submit" form="sheet-form-filters">Apply filters</button>
</footer>
</dialog>
<script>
const form = document.getElementById('sheet-form-filters');
form.addEventListener('submit', () => {
// Apply new FormData(form) here; the form then closes the sheet.
});
</script><button class="plf:btn plf:btn-outline" data-plf-trigger="modal:open" data-plf-target="sheet-form">Choose filters</button>
<dialog class="plf:modal plf:sheet" data-plf-modal id="sheet-form" aria-describedby="sheet-form-description">
<header class="plf:sheet-header">
<div>
<h2 class="plf:sheet-title">Project filters</h2>
<p class="plf:sheet-description" id="sheet-form-description">Choose the projects you want to see.</p>
</div>
<button class="plf:modal-close plf:sheet-close" data-plf-trigger="modal:close" aria-label="Close"></button>
</header>
<div class="plf:sheet-body">
<form class="plf:flex plf:flex-col plf:gap-4" id="sheet-form-filters" method="dialog">
<div class="plf:field">
<label class="plf:field-label" for="sheet-form-query">Project name</label>
<input class="plf:input" id="sheet-form-query" name="query" type="text" autofocus value="Website">
</div>
<div class="plf:field">
<label class="plf:field-label" for="sheet-form-stage">Stage</label>
<select class="plf:select" id="sheet-form-stage" name="stage" data-plf-select>
<option value="all">All stages</option>
<option value="review">In review</option>
<option value="active">Active</option>
</select>
</div>
<label><input class="plf:checkbox" type="checkbox" name="archived"> Include archived projects</label>
</form>
</div>
<footer class="plf:sheet-footer">
<button class="plf:btn plf:btn-outline" data-plf-trigger="modal:close">Close</button>
<button class="plf:btn plf:btn-primary" type="submit" form="sheet-form-filters">Apply filters</button>
</footer>
</dialog>
<script>
const form = document.getElementById('sheet-form-filters');
form.addEventListener('submit', () => {
// Apply new FormData(form) here; the form then closes the sheet.
});
</script>'use client';
import { useId, useState, type FormEvent } from 'react';
import { Button, Checkbox, Field, Input, Select, Sheet, SheetBody, SheetClose, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from '@pelatform/react';
export function Example() {
const [open, setOpen] = useState(false);
const form = useId();
function apply(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
// Apply new FormData(event.currentTarget) here.
setOpen(false);
}
return (
<>
<Button variant="outline" onClick={() => setOpen(true)}>Choose filters</Button>
<Sheet open={open} onOpenChange={setOpen}>
<SheetHeader>
<div>
<SheetTitle>Project filters</SheetTitle>
<SheetDescription>Choose the projects you want to see.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<form className="flex flex-col gap-4" id={form} onSubmit={apply}>
<Field label="Project name">
<Input name="query" type="text" autoFocus defaultValue="Website" />
</Field>
<Field label="Stage">
<Select custom name="stage">
<option value="all">All stages</option>
<option value="review">In review</option>
<option value="active">Active</option>
</Select>
</Field>
<label><Checkbox name="archived" /> Include archived projects</label>
</form>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setOpen(false)}>Close</Button>
<Button color="primary" type="submit" form={form}>Apply filters</Button>
</SheetFooter>
</Sheet>
</>
);
}'use client';
import { useId, useState, type FormEvent } from 'react';
import { Button, Checkbox, Field, Input, Select, Sheet, SheetBody, SheetClose, SheetDescription, SheetFooter, SheetHeader, SheetTitle } from '@pelatform/react/prefixed';
export function Example() {
const [open, setOpen] = useState(false);
const form = useId();
function apply(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
// Apply new FormData(event.currentTarget) here.
setOpen(false);
}
return (
<>
<Button variant="outline" onClick={() => setOpen(true)}>Choose filters</Button>
<Sheet open={open} onOpenChange={setOpen}>
<SheetHeader>
<div>
<SheetTitle>Project filters</SheetTitle>
<SheetDescription>Choose the projects you want to see.</SheetDescription>
</div>
<SheetClose />
</SheetHeader>
<SheetBody>
<form className="plf:flex plf:flex-col plf:gap-4" id={form} onSubmit={apply}>
<Field label="Project name">
<Input name="query" type="text" autoFocus defaultValue="Website" />
</Field>
<Field label="Stage">
<Select custom name="stage">
<option value="all">All stages</option>
<option value="review">In review</option>
<option value="active">Active</option>
</Select>
</Field>
<label><Checkbox name="archived" /> Include archived projects</label>
</form>
</SheetBody>
<SheetFooter>
<Button variant="outline" onClick={() => setOpen(false)}>Close</Button>
<Button color="primary" type="submit" form={form}>Apply filters</Button>
</SheetFooter>
</Sheet>
</>
);
}JavaScript
Sheet needs JavaScript. The Full script (pelatform-ui.min.js) starts every component on page load, with no code of your own; with ESM imports, call init() yourself, as in Installation. For markup you add later, see Dynamic content.
<link rel="stylesheet" href="pelatform-ui.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.min.css">
<link rel="stylesheet" href="components/button.min.css">
<link rel="stylesheet" href="components/form.min.css">
<link rel="stylesheet" href="components/modal.min.css">
<link rel="stylesheet" href="components/sheet.min.css">
<link rel="stylesheet" href="components/select.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/modal.min.js" defer></script>
<script src="components/select.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script><link rel="stylesheet" href="pelatform-ui.prefixed.min.css">
<script src="pelatform-ui.min.js" defer></script><link rel="stylesheet" href="core/pelatform-ui-core.prefixed.min.css">
<link rel="stylesheet" href="components/button.prefixed.min.css">
<link rel="stylesheet" href="components/form.prefixed.min.css">
<link rel="stylesheet" href="components/modal.prefixed.min.css">
<link rel="stylesheet" href="components/sheet.prefixed.min.css">
<link rel="stylesheet" href="components/select.prefixed.min.css">
<script src="core/pelatform-ui-core.min.js" defer></script>
<script src="components/modal.min.js" defer></script>
<script src="components/select.min.js" defer></script>
<script>document.addEventListener('DOMContentLoaded', () => PLF.init());</script>React
Sheet from @pelatform/react renders this panel on a Modal: the application opens it with open and closes it in onOpenChange, and each part is a component of its own.
| Prop | Values | Default |
|---|---|---|
side |
start, or bottom for a Drawer |
The end side |
open |
true while the sheet is open |
Required |
onOpenChange |
(open, reason), called when the sheet asks to close: trigger (its close button), keyboard (Escape) or backdrop; keep open to stay open |
None |
closeOnBackdrop |
true closes on a click outside the sheet |
false |
The parts:
| Part | Element |
|---|---|
SheetHeader |
A header with sheet-header |
SheetTitle |
An h2 with sheet-title, or another heading with level, which names the sheet |
SheetDescription |
A p with sheet-description, which describes the sheet |
SheetClose |
A button with modal-close sheet-close: the drawn x and the name Close unless given others |
SheetBody |
A div with sheet-body |
SheetFooter |
A footer with sheet-footer |
SheetHandle |
A div with sheet-handle, the bottom sheet’s handle |
Other props are the element’s own, className and ref included.
CSS variables
Except for the width and gap, each variable falls back to its Modal variable.
| Variable | Default |
|---|---|
--plf-sheet-width |
24rem, capped to the viewport |
--plf-sheet-bg, --plf-sheet-color |
Surface and text |
--plf-sheet-border |
--plf-color-border-subtle, on the inner edge |
--plf-sheet-shadow |
Large shadow |
--plf-sheet-backdrop-bg |
--plf-color-backdrop |
--plf-sheet-padding |
Space 6 (24px) |
--plf-sheet-gap |
Space 4 (16px) |
--plf-modal-radius |
0 on a sheet |