Skip to main content
Component Toolkit

Production-Ready Components

Eight modern UI components — built with the platform, no framework required. Every interaction uses HTML and CSS. Copy the code, adapt the styles.

Navigation

Popover Menu

Native popover API — no JavaScript positioning needed. Auto-dismisses on outside click, supports keyboard navigation, and uses @starting-style for smooth entry.

<button popovertarget="menu">
  Options
</button>

<div id="menu"
     popover
     role="menu">
  <button class="menu-item"
           role="menuitem">
    Open
  </button>
  <button class="menu-item"
           role="menuitem">
    Download
  </button>
</div>
[popover].menu {
  padding: 0.25rem;
  background: oklch(14% 0.02 265);
  border-radius: 0.75rem;
  opacity: 0;
  translate: 0 -0.5rem;
  transition: opacity 250ms, translate 250ms,
    display 250ms allow-discrete;

  @starting-style {
    opacity: 0;
    translate: 0 -0.5rem;
  }
}

[popover].menu:popover-open {
  opacity: 1;
  translate: 0 0;
}
Changes saved Your work has been saved successfully.
Feedback

Toast Notification

Dismissible notification using the Popover API. Enters with @starting-style, exits with a CSS transition. Fixed positioning keeps it anchored to the viewport corner.

<button
  popovertarget="toast"
  popovertargetaction="show">
  Show Toast
</button>

<div id="toast"
     class="toast"
     popover>
  <strong>Changes saved</strong>
  <span>Your work is saved.</span>
</div>
.toast {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  margin: 0;
  opacity: 0;
  translate: 0 1rem;
  transition:
    opacity 250ms,
    translate 250ms,
    display 250ms allow-discrete;

  @starting-style {
    opacity: 0;
    translate: 0 1rem;
  }
}

.toast:popover-open {
  opacity: 1;
  translate: 0 0;
}
Feedback

Modal Dialog

Native <dialog> element with closedby="any" for click-outside dismissal. Animated backdrop uses @starting-style. Fully accessible with focus trap built in.

<button
  onclick="dialog.showModal()">
  Open Modal
</button>

<dialog
  id="dialog"
  closedby="any">
  <h2>Title</h2>
  <p>Dialog content.</p>
  <button
    onclick="dialog.close()">
    Close
  </button>
</dialog>
dialog {
  opacity: 0;
  scale: 0.96;
  transition:
    opacity 250ms,
    scale 250ms,
    display 250ms allow-discrete,
    overlay 250ms allow-discrete;

  @starting-style {
    opacity: 0;
    scale: 0.96;
  }
}

dialog[open] {
  opacity: 1;
  scale: 1;
}

dialog::backdrop {
  background: oklch(5% 0 0 / 0.8);
  backdrop-filter: blur(4px);
}
Container Query Card

Reshapes automatically as its container width changes — no media queries needed.

@container
Layout

Responsive Card

Uses @container to switch between stacked and side-by-side layouts at 24rem. Resize the demo above to see it respond to its own container, not the viewport.

/* Wrap in a container */
<div class="card-container">
  <div class="card">
    <div class="card__image">
      <!-- image -->
    </div>
    <div class="card__body">
      <h3>Title</h3>
      <p>Description</p>
    </div>
  </div>
</div>
.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: grid;
  grid-template-rows: auto 1fr;
}

@container card (min-width: 24rem) {
  .card {
    grid-template-rows: none;
    grid-template-columns: 8rem 1fr;
  }
}
What is the Popover API?
A native HTML API for creating dismissible overlay UI — menus, tooltips, and dialogs — without JavaScript. Uses the popover attribute and popovertarget to wire things up declaratively.
How does @starting-style work?
It defines the initial style of an element before its first paint, enabling CSS transitions from display: none. The browser captures the start values and transitions into the final state.
Do these need JavaScript?
Nope. <details> is a native HTML element with built-in toggle behaviour. The chevron rotation and body animation are all CSS, triggered by the [open] attribute.
Navigation

Animated Accordion

Built on the native <details> + <summary> elements. Content animates in via @starting-style. Chevron rotates via CSS on the [open] attribute — zero JavaScript.

<details class="accordion-item">
  <summary>
    Question?
    <svg class="chevron">
      <!-- chevron path -->
    </svg>
  </summary>
  <div class="accordion-body">
    Answer text here.
  </div>
</details>
.chevron {
  transition: rotate 250ms ease;
}

[open] .chevron {
  rotate: 180deg;
}

.accordion-body {
  animation: slide-in 250ms ease both;

  @starting-style {
    opacity: 0;
    translate: 0 -0.5rem;
  }
}
Forms

Toggle Switch

An iOS-style toggle built from a visually-hidden checkbox. The track and thumb are styled entirely with CSS using :has(input:checked) — no JavaScript, fully keyboard accessible.

<label class="toggle">
  <input
    type="checkbox"
    class="visually-hidden">
  <span class="track"
        aria-hidden="true">
  </span>
  Notifications
</label>
.track {
  width: 2.75rem;
  height: 1.5rem;
  border-radius: 9999px;
  background: oklch(25% 0.03 265);
  transition: background 250ms;
}

.track::after {
  content: "";
  /* ...thumb styles */
  transition: translate 250ms;
}

.toggle:has(input:checked) .track {
  background: var(--color-primary);
}

.toggle:has(input:checked) .track::after {
  translate: 1.25rem 0;
}
Live preview area
The code for this component. Use :has() on the wrapper to detect which radio is checked, then show/hide panels with CSS — no JavaScript needed.
Full documentation, API reference, and accessibility notes. Each panel is a regular div hidden with display: none until its corresponding radio is checked.
Navigation

Tab Bar

Tabs driven entirely by CSS. Radio inputs paired with :has() on the wrapper control which panel is visible. Active underline is a bottom border that transitions on the label.

<div class="tabs">
  <input type="radio"
         name="t"
         id="tab-a"
         checked>
  <input type="radio"
         name="t"
         id="tab-b">

  <label for="tab-a">Alpha</label>
  <label for="tab-b">Beta</label>

  <div class="panel a">...</div>
  <div class="panel b">...</div>
</div>
.panel { display: none; }

.tabs:has(#tab-a:checked)
  .panel.a {
  display: block;
}

.tabs:has(#tab-b:checked)
  .panel.b {
  display: block;
}

.tabs:has(#tab-a:checked)
  label[for="tab-a"] {
  border-bottom-color:
    var(--color-primary);
}
Hover me
Feedback

Tooltip

Two approaches: a Popover-based tooltip that renders in the top layer (always above other content), and a CSS-only hover tooltip using opacity + translate transitions.

<!-- CSS-only hover approach -->
<div class="tip-wrapper">
  <button>Hover me</button>
  <div class="tip"
       role="tooltip">
    Tooltip text
  </div>
</div>

<!-- Popover approach -->
<button
  popovertarget="tip">
  Click me
</button>
<div id="tip"
     popover
     role="tooltip">
  Tooltip text
</div>
.tip {
  opacity: 0;
  translate: -50% 0.5rem;
  transition:
    opacity 150ms,
    translate 150ms;
}

.tip-wrapper:hover .tip,
.tip-wrapper:focus-within .tip {
  opacity: 1;
  translate: -50% 0;
}

/* Arrow via pseudo-element */
.tip::after {
  content: "";
  border: 5px solid transparent;
  border-top-color: currentColor;
}