Components

Every component in the starter, demonstrated live with code. Modern CSS features replacing JavaScript libraries — zero-JS by default, full accessibility.

Design Tokens

Single source of truth in tokens/. Built to CSS custom properties, consumed via Tailwind utilities. Every color on this page comes from the token system.

Primary

primary-500 --color-primary-500
primary-600 --color-primary-600
primary-700 --color-primary-700

Secondary

secondary-500 --color-secondary-500
secondary-600 --color-secondary-600
secondary-700 --color-secondary-700

Surfaces

background-primary --color-background-primary
background-secondary --color-background-secondary
foreground-primary --color-foreground-primary

Atoms

Primitive building blocks. Each is a single Astro component with TypeScript props, design token colors, and built-in accessibility.

Badge

Zero JS CSS Only WCAG AA

Inline label element with variant and size options. Enhanced with prefers-contrast support for users who request higher contrast.

prefers-contrast: more — heavier borders and font weight

Extra Small Primary Medium Secondary Neutral
Show Badge code Hide Badge code
<Badge variant="primary" size="sm">Primary</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="neutral">Neutral</Badge>

Button

Zero JS WCAG AA

Polymorphic button/link component. Renders as <a> when href is provided, <button> otherwise. Supports disabled state with proper aria.

Disabled state uses aria-disabled and removes from tab order

Show Button code Hide Button code
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost" size="sm">Ghost</Button>

Tooltip

Popover API Prog. Enhancement WCAG AA

Hover/focus tooltip upgraded with the Popover API. Browsers that support popover='hint' get auto-dismiss and Escape-to-close. Others fall back to CSS hover/focus.

Visible on focus + hover; Escape-to-close (Popover API)

Hover (top) Hover (bottom) Popover enhanced
Show Tooltip code Hide Tooltip code
<Tooltip text="Helpful information" position="top">
  Hover me
</Tooltip>

ScrollReveal

Scroll-Driven Zero JS CSS Only

Scroll-driven reveal animations. Replaces AOS, ScrollMagic, and GSAP ScrollTrigger with zero JavaScript. Uses animation-timeline: view() — content animates in as it enters the viewport.

prefers-reduced-motion: respected — content visible immediately

Scroll down to see these cards reveal (they use the same ScrollReveal wrapping this entire page):

slide-right
scale
slide-left
Show ScrollReveal code Hide ScrollReveal code
<ScrollReveal animation="fade-up">
  <Card>Content reveals on scroll</Card>
</ScrollReveal>

CounterBadge

CSS @property Scroll-Driven Zero JS

Animated counter using CSS @property with <integer> type and counter(). Numbers count up from 0 when scrolled into view — entirely in CSS.

role=img + aria-label exposes counter values to assistive tech

Show CounterBadge code Hide CounterBadge code
<CounterBadge value={42} suffix="+" label="Components" />

Molecules

Composite components built from atoms. Interactive patterns using native HTML elements — <dialog>, <details>, radio buttons — instead of JavaScript frameworks.

Card

@starting-style Zero JS View Transitions

Base container with optional @starting-style entry animation. When animated=true, the card fades and slides in on first render — visible during View Transitions navigation.

prefers-reduced-motion: respected — no entry animation

Standard card — no animation
Animated card — @starting-style entry
Show Card code Hide Card code
<Card animated>
  <div class="p-4">Content with entry animation</div>
</Card>

Dialog

<dialog> @starting-style WCAG AA

Native <dialog> element with ::backdrop, focus trapping, and Escape-to-close — all browser-provided. Replaces Radix Dialog, HeadlessUI, or any modal library. Entry animation via @starting-style.

Focus trap + Escape-to-close: native to <dialog>

Native Dialog Element

This dialog uses the native <dialog> element. The browser provides focus trapping, backdrop, Escape-to-close, and proper stacking context.

The entry animation uses @starting-style and transition-behavior: allow-discrete to animate from display: none.

Small Dialog

A compact dialog for confirmations or simple messages.

Show Dialog code Hide Dialog code
<Dialog id="my-dialog" title="Dialog Title" size="md">
  <p>Dialog content here</p>
</Dialog>

<button onclick="document.getElementById('my-dialog').showModal()">
  Open Dialog
</button>

Tabs

CSS Only Prog. Enhancement WCAG AA

CSS-only tab switching using hidden radio buttons — the same pattern as the Header's mobile menu checkbox. Arrow key navigation via ~15 lines of inline script (WCAG requirement).

Keyboard: arrow keys, Home, End — full WCAG tablist pattern

Panel switching is powered by CSS :has() selectors and the peer-checked: pattern. No framework state management needed.

Pass an array of tab objects. Each panel is a child with data-tab-panel matching the tab ID. The defaultTab prop sets the initially active tab.

Full ARIA support: role="tablist", role="tab", role="tabpanel", aria-selected, aria-controls. Arrow keys navigate between tabs.

Show Tabs code Hide Tabs code
<Tabs tabs={[{ id: "one", label: "Tab One" }, ...]}>
  <div data-tab-panel="one" role="tabpanel">First panel</div>
  <div data-tab-panel="two" role="tabpanel">Second panel</div>
</Tabs>

Structural

Layout components that form the page skeleton. The Grid component uses CSS Container Queries — responding to parent width instead of viewport width.

Grid (Container Queries)

Container Query Zero JS CSS Only

Responsive grid that uses @container queries instead of media queries. The grid responds to its parent container's width, not the viewport — making it truly reusable in any layout context.

Column 1
Column 2
Column 3
Show Grid (Container Queries) code Hide Grid (Container Queries) code
<Grid cols={3} gap={4}>
  <Card>Item 1</Card>
  <Card>Item 2</Card>
  <Card>Item 3</Card>
</Grid>

ParallaxSection

Scroll-Driven Zero JS CSS Only

CSS scroll-driven parallax. Decorative background shapes move at different rates than content using animation-timeline: scroll(). Replaces Rellax, Locomotive Scroll, or GSAP ScrollTrigger.

prefers-reduced-motion: respected — shapes stay static; aria-hidden on decorations

The hero section at the top of this page uses ParallaxSection. Scroll up to see the subtle background shape movement as you scroll past.

Show ParallaxSection code Hide ParallaxSection code
<ParallaxSection intensity="subtle">
  <h2>Content moves at normal speed</h2>
  <p>Background shapes drift with parallax</p>
</ParallaxSection>

Islands Architecture

CSS handles presentation. JavaScript handles state — only when you genuinely need it. This is the one island component in the showcase: Preact Signals for fine-grained reactivity with zero VDOM diffing.

SignalsCounter

Preact Signals WCAG AA

Preact Signals reactive state demo. Uses client:visible for lazy hydration — zero JS cost until the component enters the viewport. Signal updates only re-render the text nodes that changed, not the entire component tree.

aria-label on increment/decrement buttons + visible focus rings

Reactive Count

0

0Doubled
EvenParity

Preact Signals — fine-grained reactivity with zero VDOM diffing. Only the text nodes that change re-render.

Show SignalsCounter code Hide SignalsCounter code
import SignalsCounter from "@/components/islands/SignalsCounter.tsx";

<SignalsCounter client:visible />

Composition

Isolated demos prove a component renders. Compositions prove the system holds together. Below: real UI assembled from the same atoms and molecules shown above — no glue code.

Blog Post Card

Zero JS WCAG AA

Card + Badge + Tooltip + Button — the building blocks for any blog index, news feed, or content listing. Hover the date to see the Tooltip, click the button for the Card hover state.

All interactive elements keyboard-reachable; tooltip on focus + hover

Engineering CSS

Why CSS-Only Tabs Are Faster Than React Tabs

A deep dive into the radio-button pattern that powers this template's tab component — zero JavaScript, full ARIA support.

Read more →
Show Blog Post Card code Hide Blog Post Card code
<Card animated>
  <article class="p-6">
    <Badge variant="primary" size="xs">Engineering</Badge>
    <h3>Why CSS-Only Tabs Are Faster Than React Tabs</h3>
    <p>A deep dive into the radio-button pattern...</p>
    <Tooltip text="Published 4 days ago">
      <time>Apr 7, 2026</time>
    </Tooltip>
    <Button variant="ghost" size="sm" href="/blog/css-tabs/">Read more</Button>
  </article>
</Card>

Settings Panel

CSS Only <dialog> WCAG AA

Tabs + Dialog + Grid + Button — a typical app settings UI. The tabs partition concerns, the dialog handles destructive confirmations, the grid lays out option cards.

Tabs: arrow keys + Home/End. Dialog: focus trap + Escape. Both built into the components.

Theme

Follows system preference

Language

English (US)

Notifications

All enabled

Advanced settings would live here — feature flags, experimental UI, developer tools. Try the arrow keys to navigate between tabs.

Reset all settings?

This will restore all settings to their defaults. This action cannot be undone.

Show Settings Panel code Hide Settings Panel code
<Tabs tabs={[
  { id: "general", label: "General" },
  { id: "advanced", label: "Advanced" },
]}>
  <div data-tab-panel="general">
    <Grid>
      <Card>Theme</Card>
      <Card>Language</Card>
    </Grid>
    <Button onclick="confirmDialog.showModal()">Reset all</Button>
  </div>
</Tabs>

<Dialog id="confirm-reset" title="Reset all settings?">
  <p>This cannot be undone.</p>
</Dialog>