Spectre UI Astro
Astro-native components for the Spectre UI design system — SSR-safe, token-driven, and ready to drop into any Astro project.
@phcdevworks/spectre-ui-astro (current version 3.1.0) provides
Astro-native components for Spectre UI. Drop Spectre components
into any Astro project — SSR, SSG, or hybrid — without writing CSS, redefining
tokens, or reimplementing recipe logic.
What Astro developers get
- Twenty-three ready-to-use Astro components — alerts, avatars, badges, buttons, cards, containers, dropdowns, footers, grids, icon boxes, inputs, modals, navs, pricing cards, ratings, sections, sidebars, spinners, stacks, tags, testimonials, toasts, and tooltips
- SSR-safe by default — deterministic markup and stable accessibility
wiring. Every component ships no client-side JavaScript except
SpSidebar, which owns its own toggle/backdrop interaction via a small scoped inline<script> - Thin wrapper pattern — styling comes entirely from Spectre UI; this package adds Astro slots, typed props, and framework ergonomics
- Re-exported recipe helpers — use the same class functions the components use, directly from your Astro frontmatter or TypeScript
Installation
npm install @phcdevworks/spectre-ui-astro @phcdevworks/spectre-ui
@phcdevworks/spectre-ui is a required peer dependency. It owns the CSS,
class recipes, and design system behavior that powers every component in this
package. Install this package inside an Astro project; astro is also a peer
dependency supplied by the consuming app.
If your project works with Spectre design tokens directly:
npm install @phcdevworks/spectre-tokens
CSS setup
This package ships no CSS. Add the Spectre UI stylesheet once in your Astro layout:
---
// src/layouts/BaseLayout.astro
import '@phcdevworks/spectre-ui/index.css'
interface Props {
title?: string
}
const { title = 'My Astro site' } = Astro.props
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
</head>
<body>
<slot />
</body>
</html>
All Spectre components pick up the stylesheet through the layout. Do not import it per-component — CSS ownership stays with Spectre UI.
Quick start
---
import BaseLayout from '../layouts/BaseLayout.astro'
import {
SpBadge,
SpButton,
SpCard,
SpIconBox,
SpInput,
SpPricingCard,
} from '@phcdevworks/spectre-ui-astro'
---
<BaseLayout title="My page">
<SpCard variant="elevated">
<SpIconBox variant="primary" size="md">
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 2l7 4v12l-7 4-7-4V6l7-4z" fill="currentColor" />
</svg>
</SpIconBox>
<SpBadge variant="success" size="sm">Stable</SpBadge>
<h2>Build faster with Spectre</h2>
<SpButton variant="primary" size="lg">Get started</SpButton>
</SpCard>
<SpInput
id="email"
label="Email"
name="email"
type="email"
placeholder="you@example.com"
helperText="We will never share your email."
/>
<SpPricingCard featured>
<h3 slot="header">Pro</h3>
<span slot="price">$29/mo</span>
<span slot="description">For growing teams.</span>
<SpButton variant="primary" fullWidth>Choose plan</SpButton>
</SpPricingCard>
</BaseLayout>
Polymorphic rendering (as prop)
Most components accept an as prop to change the rendered HTML element
without changing component behavior or styling.
<!-- SpButton: renders <button> by default -->
<SpButton variant="primary">Submit</SpButton>
<!-- SpButton: renders <a> with all button styling -->
<SpButton variant="primary" as="a" href="/get-started">Get started</SpButton>
<!-- SpCard: semantic article markup -->
<SpCard variant="elevated" as="article">
<h2>Article title</h2>
</SpCard>
<!-- SpBadge: inline time element -->
<SpBadge variant="primary" as="time" datetime="2026-01-01">Jan 2026</SpBadge>
- Disabled navigation: When
disabledis set on an anchor (as="a"), thehrefis suppressed so the element is not keyboard-navigable.aria-disabled="true"is always set alongsidedisabled. - Button type: When
as="button"(the default forSpButton),typedefaults to"button"to prevent accidental form submission. Passtype="submit"explicitly when needed. - Non-native interactive elements: Setting
interactive={true}on adivorspanaddsrole="button"andtabindex="0"automatically. Use this only when a nativebuttonorais genuinely impractical.
SSR and static site behavior
This package works in all Astro output modes: "static", "server", and
"hybrid".
- No client-side JavaScript. Every component renders entirely at build time or in the server step. No hydration directives are needed or used. Interactive styles (hover, focus, active) are driven by CSS from Spectre UI.
- Deterministic markup. All IDs, class names, and attributes are computed from explicit props. Every render of the same props produces identical HTML — safe for SSR streaming and static generation.
SpInputexplicitidrequirement. When any oflabel,helperText, orerrorMessageare passed, an explicitidprop is required. Without it, the component throws during render to prevent nondeterministicfor/aria-describedbywiring in server-rendered and statically generated output.
<!-- id is required whenever label, helperText, or errorMessage is set -->
<SpInput id="email" label="Email" name="email" />
CSS is handled by importing the Spectre UI stylesheet in your Astro layout once — Astro bundles and injects it in both SSR and static builds. No runtime style injection occurs from this package.
Recipe helpers
The package re-exports class recipe functions from Spectre UI. Use these when you need Spectre-aligned class names outside of the Astro components — in layout markup, in headless patterns, or when mapping over dynamic data.
---
// Using getButtonClasses to style plain anchor tags in a nav
import { getButtonClasses } from '@phcdevworks/spectre-ui-astro'
const navClass = getButtonClasses({ variant: 'ghost', size: 'sm' })
const links = [
{ href: '/', label: 'Home' },
{ href: '/about', label: 'About' },
{ href: '/blog', label: 'Blog' },
]
---
<nav>
{links.map(link => (
<a class={navClass} href={link.href}>{link.label}</a>
))}
</nav>
What this package owns
- Astro-native component delivery for Spectre UI recipes and classes
- Astro-friendly, SSR-safe component interfaces and composition patterns
- Type-safe framework bindings for the upstream Spectre UI contract
- Adapter-level ergonomics that make Spectre UI straightforward to consume in Astro projects
Golden rule: bind the upstream Spectre UI contract for Astro, do not redefine it.
What this package does not own
- Design values or token meaning — Spectre Tokens
- Core CSS, utilities, Tailwind helpers, or class recipe logic — Spectre UI
- Local styling systems that diverge from the shared Spectre contract
When to use this package
- you are building an Astro project and want Spectre UI components as first-class Astro components
- you need SSR-safe, type-safe component interfaces that bind the upstream Spectre UI recipe contract without reimplementing it
- you want to compose with Spectre’s shared recipe helpers from TypeScript in an Astro project
When not to use this package
- you are using a different framework (React, Vue, Svelte, etc.) — this package is Astro-only. Consider Spectre Components for framework-agnostic web components instead
- you want to define custom tokens or override Spectre’s design values — that belongs in Spectre Tokens
- you want to add or change class recipes, CSS utilities, or Tailwind helpers — that belongs in Spectre UI
- you need a framework-agnostic styling contract — consume Spectre UI directly
Relationship to the rest of Spectre
| Package | Owns |
|---|---|
| Spectre Tokens | Design values, semantic token meaning, and token contracts |
| Spectre UI | CSS, utilities, Tailwind helpers, and type-safe class recipes |
| Spectre Components | Framework-agnostic Lit web component behavior |
| Spectre UI Astro | Astro-native adapter delivery and framework ergonomics |
Tokens define meaning. UI defines the styling contract. Components define framework-agnostic custom element behavior. This package defines Astro delivery and consumes the upstream UI contract directly.
For the full component reference (props, slots, and examples for all 23 components), package exports, and stability table, see the Spectre UI Astro reference.