Skip to content

Tailwind CSS

helix-ui is not a Tailwind replacement. The two solve different problems, and a lot of teams want both:

  • helix-ui ships components, tokens, an a11y baseline, and a theme engine.
  • Tailwind ships layout utilities (flex, grid, gap-4, md:px-6) that are awkward to express any other way.

This page shows how to use them together without fighting either.

Install both

Terminal window
npm install @helix-ui/core @helix-ui/tokens @helix-ui/icons tailwindcss postcss autoprefixer
npx tailwindcss init -p

Mirror helix-ui tokens into Tailwind’s theme

This is the key step, and @helix-ui/tokens does it for you. It ships a Tailwind preset so you never hand-copy var() mappings. Utilities like bg-brand-500, p-4, rounded-lg, shadow-md, and text-primary resolve to the exact same helix-ui token variables the components use — which means they follow DNA themes and dark mode automatically, because every value is a live var(--helix-ui-…) reference, not a baked-in hex.

Tailwind v3

Add the preset. It only sets theme.extend (pure data, no plugins), so it composes cleanly with the rest of your config:

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
presets: [require('@helix-ui/tokens/tailwind')],
content: [
'./index.html',
'./src/**/*.{ts,tsx,js,jsx}',
// Match helix-ui's own component source so Tailwind doesn't purge
// utilities that exist inside @helix-ui/core's CSS files.
'./node_modules/@helix-ui/core/dist/**/*.{js,mjs,css}',
],
// Tailwind's reset clashes with helix-ui's component CSS — see below.
corePlugins: { preflight: false },
};

Tailwind v4

There’s no JS config in v4 — import the generated @theme stylesheet instead. It maps helix-ui tokens onto Tailwind’s theme variables:

src/index.css
@import '@helix-ui/tokens/css';
@import '@helix-ui/tokens/tailwind.css';
@import 'tailwindcss';

Order matters: @helix-ui/tokens/css declares the --helix-ui-* variables that the @theme block references, so it comes first.

What the preset gives you

Both entry points wire up the same helix-ui token families:

Tailwind themehelix-ui tokensExample utilities
colorsbrand / neutral / danger / success / warning rampsbg-brand-500, text-neutral-700, border-danger-500
backgroundColorsemantic surfaces + action fillsbg-surface, bg-surface-subtle, bg-brand, hover:bg-brand-hover
textColortext roles + on-fill + brand texttext-primary, text-muted, text-on-brand
borderColorborder rolesborder (default), border-focus, border-strong
spacingspace scale (density-aware)p-4, gap-6, mt-2
borderRadiusradius scalerounded, rounded-lg, rounded-full
fontFamily / fontSizetype tokensfont-sans, text-lg
boxShadowelevation tokensshadow, shadow-md

The semantic names in the v4 @theme block are prefixed for v4’s single flat color namespace: bg-surface, text-fg-muted, border-border-focus.

The corePlugins.preflight: false is the one non-obvious bit — Tailwind’s CSS reset (@tailwind base) nukes some defaults helix-ui relies on. If you’re moving an existing Tailwind project to helix-ui, this line prevents a wave of subtle visual breakage.

Import both stylesheets

On Tailwind v3, pull in helix-ui’s stylesheets alongside the Tailwind layers (v4 users already did this above, plus @helix-ui/tokens/tailwind.css):

src/index.css
@import '@helix-ui/tokens/css';
@import '@helix-ui/core/styles.css';
@tailwind components;
@tailwind utilities;

helix-ui’s stylesheet ships first so Tailwind utilities can override.

Use them in tandem

import { Button, Card, Stack } from '@helix-ui/core';
function PaymentRow({ amount, status }: Props) {
return (
// helix-ui Card + Stack handle the design system. Tailwind handles
// the page layout.
<Card className="md:col-span-2">
<Stack direction="row" align="center" justify="between" className="gap-4">
<div className="text-brand">{amount}</div>
<Button>Pay</Button>
</Stack>
</Card>
);
}

Rule of thumb:

Use helix-ui forUse Tailwind for
Buttons, inputs, cards, dialogs, popoversGrid spans, responsive breakpoints
Color, radius, typography, motionMargins, padding overrides at breakpoints
Anything that should be themable via DNAAnything that’s “just layout”

When the cascade fights

If you find yourself writing !bg-brand-500 to override a helix-ui component’s background, that’s a smell — the right move is to pass helix-ui’s own variant / tone prop. Tailwind override should be for layout properties, not visual ones.

// ❌ Fighting the cascade
<Button className="!bg-purple-600">Save</Button>
// ✅ Use helix-ui's API
<Button tone="brand" variant="solid">Save</Button>
// ✅ Tailwind for layout
<Button className="w-full md:w-auto">Save</Button>

What you give up

  • Two stylesheets to ship. Together they’re ~30 KB gzip. Tradeoff for the breadth.
  • Two mental models for color. helix-ui’s tokens are the source of truth; the Tailwind names mirror them. Don’t author colors in two places.

Migrating from Tailwind-only

A typical path:

  1. Install helix-ui.
  2. Set corePlugins.preflight: false.
  3. Replace your hand-rolled <button className="bg-blue-600 px-4 py-2 ...">s with <Button>.
  4. Keep your layout utilities (grid, flex, md:*) — they’re still useful.
  5. Move your colors into helix-ui tokens so DNA themes Just Work.

The migration is incremental. You don’t have to do it all at once.