Tailwind CSS
Keep Lumen's accessible controls and semantic themes. Add Tailwind for responsive composition and focused presentation changes through class or className.
1. Connect your styles
The optional tailwind.css bridge is available from Lumen 4.3. It adds semantic color utilities to an existing Tailwind v4 build. Lumen's standalone stylesheet continues to work without Tailwind.
Install your Lumen adapter, then set up Tailwind using its Vite integration for Astro or React with Vite, or its PostCSS integration for Next.js. In Astro, register tailwindcss() in vite.plugins.
pnpm add @santi020k/lumen-astro
pnpm add -D tailwindcss @tailwindcss/vitepnpm add @santi020k/lumen-astro
pnpm add -D tailwindcss @tailwindcss/viteKeep all four imports in one global CSS entry, in this order. Load that file once from your root layout or app entry. Choose the adapter you installed:
@import "@santi020k/lumen-astro/layers.css";
@import "tailwindcss";
@import "@santi020k/lumen-astro/styles.css";
@import "@santi020k/lumen-astro/tailwind.css";@import "@santi020k/lumen-react/layers.css";
@import "tailwindcss";
@import "@santi020k/lumen-react/styles.css";
@import "@santi020k/lumen-react/tailwind.css";@import "@santi020k/lumen-elements/layers.css";
@import "tailwindcss";
@import "@santi020k/lumen-elements/styles.css";
@import "@santi020k/lumen-elements/tailwind.css";The first import establishes the cascade before Tailwind's reset. Lumen's components then retain their defaults, while the final utilities layer can override presentation. The bridge maps colors; it does not import Tailwind, reset styles, or component CSS.
Keep the usual runtime setup: mount UIPrimitives once in an Astro root layout; use React components normally; call defineLumenElements() once for Elements. Follow the Astro, React, or Elements guide. The CLI also prints this setup with lumen init --framework astro --tailwind.
2. Compose with utilities
Use component props for variants, sizes, disabled states, and behavior. Use utilities for local spacing, width, responsive layout, and presentation. Astro and Elements accept class; React accepts className.
---
import { ButtonLink, Card } from '@santi020k/lumen-astro'
---
<Card class="rounded-none p-6 sm:p-8">
<h3 class="text-xl font-bold text-ink">Your next project</h3>
<p class="text-ink-soft">Accessible components, your layout.</p>
<ButtonLink href="/projects" class="w-full sm:w-auto sm:self-start">
View projects
</ButtonLink>
</Card>import { ButtonLink, Card } from '@santi020k/lumen-react'
export function ProjectCard() {
return (
<Card className="rounded-none p-6 sm:p-8">
<h3 className="text-xl font-bold text-ink">Your next project</h3>
<p className="text-ink-soft">Accessible components, your layout.</p>
<ButtonLink href="/projects" className="w-full sm:w-auto sm:self-start">
View projects
</ButtonLink>
</Card>
)
}<lumen-card class="rounded-none p-6 sm:p-8">
<h3 class="text-xl font-bold text-ink">Your next project</h3>
<p class="text-ink-soft">Accessible components, your layout.</p>
</lumen-card>The live card has square corners and responsive padding. Its link fills the available width on phones. Tailwind changes those properties while Lumen still supplies the component structure and keyboard focus treatment.
3. Share one semantic palette
The bridge exposes canvas, surface, surface-muted, surface-strong, line, ink, ink-soft, ink-muted, brand, brand-solid, brand-soft, on-brand, accent, success, warning, danger, and on-danger.
Use them anywhere Tailwind accepts a color: bg-surface, text-ink, border-line, ring-brand, or bg-brand/10. Pair bg-brand-solid with text-on-brand and bg-danger with text-on-danger; check contrast for your theme overrides.
<Card data-theme="lumen-dark" class="bg-surface text-ink">
<p class="text-ink-soft">This surface follows its local Lumen theme.</p>
</Card><Card data-theme="lumen-dark" class="bg-surface text-ink">
<p class="text-ink-soft">This surface follows its local Lumen theme.</p>
</Card>Aliases use @theme inline, so colors resolve where the utility is used, including nested data-theme scopes. Set your theme on the root for the whole app. Semantic color utilities already follow that theme without dark: classes. The bridge does not change Tailwind's dark variant; configure that variant separately if you use it for structural changes.
Customize through public hooks
Prefer props and semantic tokens first, then documented component variables or stable data-slot parts. For example, tune the card's padding with a custom property utility:
<Card class="[--ui-card-padding:2rem]">
Content with the documented Card padding hook.
</Card><Card class="[--ui-card-padding:2rem]">
Content with the documented Card padding hook.
</Card>For compound components, place utilities on the public part you want to style. With Elements, a host class styles the custom element; it does not automatically style an internal input or button. Consult the component's public parts instead of targeting private .ui-* selectors. Preserve visible focus, readable contrast, and usable touch targets.
Choose whether to include Preflight
The standard Tailwind import includes Preflight, which resets native headings, lists, borders, and form styles across your app. If you already own a reset, omit Preflight and import Tailwind's theme and utilities separately:
@import "@santi020k/lumen-astro/layers.css";
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/utilities.css" layer(utilities);
@import "@santi020k/lumen-astro/styles.css";
@import "@santi020k/lumen-astro/tailwind.css";@import "@santi020k/lumen-astro/layers.css";
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/utilities.css" layer(utilities);
@import "@santi020k/lumen-astro/styles.css";
@import "@santi020k/lumen-astro/tailwind.css";Keep the Lumen layer prelude first in either setup. Follow Tailwind's Preflight guide when choosing the reset for your application.
When a utility does not apply
- Missing color utilities: confirm that the matching
tailwind.cssbridge is imported and your CSS passes through Tailwind v4. It is a build-time stylesheet, not a browser-only import. - Utilities lose to defaults: put
layers.cssbefore the first Tailwind or Lumen stylesheet. Keep imports together and remove duplicate component stylesheet imports from JavaScript. - Utilities are absent: keep complete class names in source. Use a map of literal classes instead of building names such as
`bg-${color}`. In a monorepo, configure@sourcefor your own shared UI files. - Should I scan Lumen's package? No. Lumen ships its component CSS. Tailwind only needs to scan the consumer files where you write utilities.
- An override still loses: inline styles, unlayered app CSS, and important declarations can take precedence. Inspect the computed style and use a documented hook where the component owns that value.
- Using Tailwind v3? This bridge uses v4's
@themedirective. Keep standalone Lumen CSS and your existing v3 setup, or migrate Tailwind before adopting the bridge.
See Tailwind theme aliases and source detection for the underlying build behavior.