overlays
Sheet
A panel that slides in from an edge of the screen, for filters, navigation or details.
Native behaviorUses built-in HTML behavior, so you write no script.
Usage
A native <dialog> with ca-sheet--end, opened with commandfor and command="show-modal", like a dialog.
<button class="ca-button ca-button--outline ca-button--md" type="button" commandfor="lesson-filters" command="show-modal">Filter lessons</button>
<dialog class="ca-sheet ca-sheet--end" id="lesson-filters" aria-labelledby="lesson-filters-title">
<h2 class="ca-sheet__title" id="lesson-filters-title">Filter lessons</h2>
<div class="ca-sheet__body">
<fieldset class="ca-field">
<legend class="ca-field__label">Instructor</legend>
<label class="ca-checkbox"><input class="ca-checkbox__input" type="checkbox" name="instructor" value="anna" checked /> Anna de Boer</label>
<label class="ca-checkbox"><input class="ca-checkbox__input" type="checkbox" name="instructor" value="bram" /> Bram Visser</label>
</fieldset>
</div>
<div class="ca-sheet__footer">
<button class="ca-button ca-button--ghost ca-button--md" type="button" commandfor="lesson-filters" command="close">Cancel</button>
<button class="ca-button ca-button--primary ca-button--md" type="button" commandfor="lesson-filters" command="close" autofocus>Show lessons</button>
</div>
</dialog>Examples
From the start edge
ca-sheet--start suits navigation on small screens.
<button class="ca-button ca-button--outline ca-button--md" type="button" commandfor="school-menu" command="show-modal">Open the menu</button>
<dialog class="ca-sheet ca-sheet--start" id="school-menu" aria-labelledby="school-menu-title">
<h2 class="ca-sheet__title" id="school-menu-title">Drive School</h2>
<nav class="ca-sheet__body" aria-label="School">
<ul class="ca-sidebar__list">
<li><a class="ca-sidebar__link" href="#lessons" aria-current="page">Lessons</a></li>
<li><a class="ca-sidebar__link" href="#students">Students</a></li>
<li><a class="ca-sidebar__link" href="#invoices">Invoices</a></li>
</ul>
</nav>
<div class="ca-sheet__footer">
<button class="ca-button ca-button--ghost ca-button--md" type="button" commandfor="school-menu" command="close">Close the menu</button>
</div>
</dialog>From the bottom
ca-sheet--bottom suits short details on phones; it is as tall as its content, up to 85% of the screen.
<button class="ca-button ca-button--outline ca-button--md" type="button" commandfor="lesson-details" command="show-modal">Show lesson details</button>
<dialog class="ca-sheet ca-sheet--bottom" id="lesson-details" aria-labelledby="lesson-details-title" aria-describedby="lesson-details-description">
<h2 class="ca-sheet__title" id="lesson-details-title">Tuesday, 09:00</h2>
<p class="ca-sheet__description" id="lesson-details-description">Highway practice with Sam in the blue car, 90 minutes.</p>
<div class="ca-sheet__footer">
<button class="ca-button ca-button--primary ca-button--md" type="button" commandfor="lesson-details" command="close" autofocus>Close details</button>
</div>
</dialog>Guidance and accessibility
When to use
- Use a sheet for a task beside the page, such as filtering a list, or for navigation on small screens.
- For a short decision, use a dialog; for content people come back to, use a page.
Accessibility
- It is a native modal
<dialog>: the browser keeps focus inside, closes it on Escape, makes the page behind it inert and returns focus to the button that opened it. - Give it a title connected with
aria-labelledby, and a button that closes it in words. - Edges are logical: in right-to-left layouts the end edge is the left.
Classes
Generated from the component contract. Parts use __, modifiers use --.
| Class | Kind | Use it for |
|---|---|---|
ca-sheet | Component | The <dialog> pinned to one edge, as tall or wide as the screen. |
ca-sheet__title | Part | Heading of the sheet; connect it with aria-labelledby. |
ca-sheet__description | Part | Optional explanation below the title. |
ca-sheet__body | Part | The content; it scrolls while title and footer stay in view. |
ca-sheet__footer | Part | Row of actions at the end of the sheet. |
ca-sheet--end | Layout | Slides from the end edge (the right in left-to-right). |
ca-sheet--start | Layout | Slides from the start edge. |
ca-sheet--bottom | Layout | Slides up from the bottom. |
Skins
The same markup, dressed by each skin. Structure and behavior stay the same; only the look changes.
Base skin
Neutral grayscale starting point; product skins extend it and change what differs.
Calaca skin
The Calaca UI brand: hueso paper and tinta ink, cempasúchil marigold, rosa and jade.
Proof skin
Pilot skin pushed far from base: square, heavy, offset shadows, larger targets.
Crossview skin
The CrossView proofing table: cool ground, bond-paper sheets, rule-grey hairlines, one red mark.
Framework notes
Link the prebuilt stylesheet of your skin next to your brand theme. No build step.
<link rel="stylesheet" href="theme.css" />
<link rel="stylesheet" href="ca-base.css" />In Astro, Vite and other Tailwind projects, import Calaca after Tailwind and your theme in your main stylesheet.
@import "tailwindcss";
@import "./theme.css";
@import "@calaca/ui/core.css";
@import "@calaca/ui/skins/base.css";Same stylesheet as above; write the classes in className.
<button className="ca-button ca-button--primary ca-button--md" type="button">Save changes</button>Add the commands polyfill once per page, for browsers without native invoker commands. In Astro or Next.js, import @calaca/ui/behavior/commands once in the layout.
<script type="module" src="ca-commands.js"></script>