Single-purpose UI elements.
These are common, non-complex UI elements that just need a class or two. Forms, cards, buttons, and more.
Button styling for `<button>` elements and `.button` class for links.
When to use: Buttons and links styled as actions.
Classes: .button, .primary, .success, .warning, .error, .ghost, .minimal, .dark, .light, .contrast, .mini
.dark, .light, and .contrast keep a fixed surface regardless of theme. Use them on buttons that need to sit on a particular surface (e.g., a .dark hero) and stay legible.
.reset is a general-purpose utility (not a button variant) for stripping native chrome from any element. It removes background, border, radius, shadow, and padding while inheriting typography and color — useful when you want a <button> to behave like a bare interactive surface.
Interactive pill-shaped elements for filters, categories, and selections.
When to use: Selectable pills for filters and segmented choices.
Classes: .chip, .selected, .mini
Use for multi-select interfaces, tag filters, or skill selectors.
Icons are automatically sized to 1em.
border-radius: var(--br-xxl)var(--border-1)--fl: -1 (smaller text)Subtle category labels with customizable colors.
When to use: Status or category labels.
Classes: .tag, .success, .warning, .error, .info, .muted
Use for metadata, categories, or status indicators.
For custom categories, use --tag-color as a fallback when semantic variants are not a fit:
Available colors: --red, --orange, --yellow, --green, --teal, --blue, --indigo, --purple, --pink, --gray, --slate
Icons are automatically sized to 1em.
--tag-color via OKLCH lightness/chroma adjustments (theme-aware in light and dark)--tag-color--fl: -1 (smaller text)border-radius: var(--br-xxl)<a>/<button>) lift 1px on hover (translate: 0 -1px)Circular avatar for user images or initials.
When to use: User photos or initials with size variants.
Classes: .avatar, .xs, .s, .l, .xl, .bordered
border-radius: 50%)object-fit: cover--fg-1)Container styles for cards and content blocks.
When to use: Container surface styles and quick panel variants.
Classes: .box, .glow, .semi-gloss, .ghost, .invisible
.box - Tint background, padding, border-radius, border.box.glow - Applies var(--box) — a soft outer drop shadow plus two inset highlights for a subtle dimensional sheen.box.semi-gloss - Gradient background, premium feel.box.ghost - Transparent, border outline only.box.invisible - No visual styling, just structureInformational boxes for tips, warnings, errors, and success messages.
When to use: Inline informational or status callout blocks.
Classes: .callout, .warning, .error, .success, .ghost, .fill, .callout.stack
The first direct <svg> child is pulled into the gutter and colored with
--callout-accent:
Add .stack directly to the callout to align children to the start and stack them with consistent spacing:
A nested <div class="stack"> works too if you need finer control over which children stack.
--callout-tint - Background color (applies to .fill only)--callout-accent - Icon colorA padded surface for grouped content. Reach for header, footer, or media only when you need a divided bar or edge-to-edge media.
When to use: Grouped content, linked previews, and pricing tiles.
Classes: .card, .card.linked, .card.featured
The card itself is the padded surface — drop content directly inside. No wrapper, no body class.
Children stack vertically with a small built-in gap. Override it inline with --gap when you want more breathing room:
Add a direct <header> or <footer> only when you want a divided bar with a separator. They bleed edge-to-edge through the card's padding automatically.
Direct <img>, <picture>, or <figure> children bleed edge-to-edge too. At the top or bottom of the card they extend through that side's padding.
.card is the padded surface. Don't wrap content in an extra <div>.gap: var(--gap, var(--vs-s)). Override with style="--gap: var(--vs-m);".<header>, <footer>, and <img>/<picture>/<figure> direct children bleed to the card edge — use them only when you actually want that treatment.Chat-friendly message container with configurable colors, width, and spacing.
When to use: Chat message presentation and conversation snippets.
Classes: .bubble, .chat-thread, .chat-row, .chat-row.self, .chat-message, .chat-composer
.bubble is a rounded chat container with configurable padding, max-width, and child flow spacing.
Use these helpers to build complete chat threads:
.chat-thread - Vertical message stack with configurable spacing/padding.chat-row - Left-aligned row.chat-row.self - Right-aligned row.chat-message - Width-constrained wrapper for each message.chat-composer - Composer row where .input-group expands to fill space--bubble-bg - Bubble background color--bubble-border - Bubble border color--bubble-max-inline - Max bubble width--bubble-pad-block - Block-axis padding--bubble-pad-inline - Inline-axis padding--bubble-radius - Corner radius--bubble-flow-space - Spacing between child elementsHorizontal scrolling with CSS scroll-snap. No JavaScript required.
When to use: Horizontal scroll-snap for cards or media strips.
Classes: .carousel
display: flex with horizontal overflowscroll-snap-type: x mandatory for snappingscroll-snap-align: startscrollbar-width: thin)Vertical scrolling with CSS scroll-snap. Like carousel but vertical.
When to use: Vertical scroll-snap list or feed.
Classes: .reel
--reel-height - Container height (default: 80vh)--gap - Gap between panels (default: 1rem)display: flex with flex-direction: columnscroll-snap-type: y mandatory for snappingscroll-snap-align: startResponsive table wrapper with clean data table styling.
When to use: Responsive table wrapper and default table styling.
Classes: .table, .table.zebra
The .table wrapper provides:
overflow-x: auto for responsiveness--table-border - Custom border-radius for wrapperNative HTML `<dialog>` element with open/close animations.
When to use: Native modal flows and confirmations.
Classes: dialog, .close
No JavaScript required when using HTML invokers.
commandfor points to the dialog's idcommand="show-modal" opens the dialog as a modalcommand="close" closes the dialogThe .close class creates a circular red button. When it is a direct child of a <dialog>, an extra rule pins it to the top-right corner (slightly overlapping the dialog's top edge). Used outside a <dialog>, it's just the circular button — position it yourself.
max-width: 40ch - Character-based width for good proportionsPure CSS tabs using `<details>` and `<summary>` with CSS Grid and Subgrid.
When to use: CSS-only tabbed content using details/summary.
Classes: .tabs, .tabs.boxed, .tabs.pill
No JavaScript required.
name attribute on <details> ensures only one tab can be open at a time (native HTML behavior)--n CSS variable positions each tab's summary in the correct grid column--tab-count on the container sets the number of columns (default: 3)name attributeopen to the tab that should be visible initially--tab-count to match@starting-styleHover tooltips using CSS anchor positioning. No JavaScript required.
When to use: Popover-based tooltips with CSS anchor positioning.
Classes: .tooltip, .tooltip-content, .bottom, .left, .right
anchor-scope, position-anchor, position-area)var(--bg)var(--border-1)var(--shadow-3):hover and :focus-within:focus-within) for keyboard usersNavigation list with clickable rows for settings pages, menus, and navigation indexes.
When to use: Grouped list-style navigation rows.
Classes: .list-nav
Each item is a pill-shaped card with subtle shadow.
Items are direct <a> or <button> children of .list-nav. No additional classes needed.
Each item can contain:
<svg> - Icon on the left (sized to 1.25em)<small> - Optional description (muted, smaller text)Each item automatically gets:
var(--br-xxl) rounded cornersvar(--shadow-2) for elevated card appearancevar(--bg) for proper themingvar(--pad-m) spacing between itemsvar(--border-1) border for definition| Feature | List Nav | Sidebar Nav |
|---|---|---|
| Item style | Individual cards with shadow | Flat items in a list |
| Description | Supported via <small> | Not supported |
| Use case | Standalone navigation rows | Sticky sidebar menus |
| Nesting | Not supported | Supports details/summary |
| Visual weight | Higher (cards with shadow) | Lower (compact) |
<nav> container<a> for navigation links, <button> for actionsdisabled attributearia-disabled="true" when neededAccessible toggle/switch input using native checkbox.
When to use: Boolean settings with checkbox semantics.
Classes: .toggle, .compact
<span id="forms">
--toggle-color - Color when checked (default: var(--primary))--toggle-width - Track width--toggle-height - Track heightThe toggle uses a native checkbox, so it:
prefers-reduced-motionInput field with connected button.
When to use: Input plus attached action button patterns.
Classes: .input-group, .input-group.stack-mobile
Use for copy-to-clipboard, search with button, URL sharing, or any input that needs an action.
Add .stack-mobile to break the group into a vertical stack below 640px. Each child reclaims a full border-radius so the input and button read as separate controls.
.primary, .ghost, etc.)Search input with icon positioned inside.
When to use: Search field with icon and compact action behavior.
Classes: .search
Get icons from Phosphor Icons. The magnifying glass icon shown above is the "MagnifyingGlass" icon.
var(--fg-3)) so the user's typed text reads as the primary contentDrag-and-drop file upload zone with click-to-upload fallback.
When to use: Drag-and-drop upload zones with native fallback.
Classes: .dropzone, .dragover
Get icons from Phosphor Icons. The upload icon shown above is the "UploadSimple" icon.
var(--pad-xxxl), radius: var(--br-l) (hardcoded; theme by editing the source or wrapping)2px dashed var(--fg-2)).dragover state swaps border and icon colour to var(--accent)