registyle

Write Tailwind utilities once. Use semantic class names everywhere.
1,390 1
Install
npm install registyle
Latest Version:2.1.1
License:MIT
Last Updated:Oct 6, 2026
Links: GitHub  ·  npm
Maintainer: bigetion

registyle

npm version npm downloads License: MIT Open in StackBlitz

A semantic styling library that compiles Tailwind CSS v4 utilities into named component classes, with a separate CSS-only runtime for plain declarations.

ESM only. This package requires Node.js 18+ and a bundler that supports ES Modules (Vite, webpack 5, Rollup, esbuild). CommonJS require() is not supported.

See CHANGELOG for version history.

Try It Online

▶ Open in StackBlitz — no install needed, runs in your browser.

Features

  • Compile Tailwind utilities onto semantic selectors such as .action-button and .action-button-primary
  • Register component slots with register.group()
  • Use utility arrays and grouped prefixes such as max-sm:(w-full flex-col)
  • Compose conditional class names with cx() or generate variant registrations with registyle/variants
  • Choose a Vite plugin, a manual compiler step, or the CSS-only runtime
  • Extract runtime CSS for server-side rendering

Install

npm install registyle

How It Works

For a React app, the Vite plugin is the shortest path:

registration files -> Vite collects styles -> Tailwind v4 compiles utilities -> virtual CSS -> semantic classes in JSX

You write register() calls in JavaScript modules. The plugin collects them from src/registyles/index.js and exposes compiled CSS as virtual:registyle.css. You do not create a manifest by hand. Registyle compiles only registered utilities; it does not scan JSX or HTML for class names, and its stylesheet does not include Tailwind Preflight.

For apps without Vite, use compileToFile() in a build script. If you do not need Tailwind, use the CSS-only runtime API instead.

Quick Start: React + Vite

Create a React app if you do not already have one:

npm create vite@latest my-app -- --template react
cd my-app
npm install
npm install registyle
npm install -D @tailwindcss/postcss postcss postcss-selector-parser

Vite's React template already includes Vite and @vitejs/plugin-react. Add the Registyle plugin to vite.config.js:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { registyle } from 'registyle/vite';

export default defineConfig({
  plugins: [react(), registyle()],
});

Create src/registyles/button.js and register a component style:

import { register } from 'registyle/collector';

register('action-button', {
  base: {
    tw: [
      'inline-flex items-center rounded-md',
      'px-4 py-2 font-medium',
    ],
  },
  modifiers: {
    primary: { tw: 'bg-blue-600 text-white hover:bg-blue-700' },
    secondary: { tw: 'bg-gray-100 text-gray-900' },
  },
});

Create src/registyles/index.js to collect the styles. The Vite plugin uses this entry by default:

import { getManifest } from 'registyle/collector';
import './button.js';

export default getManifest();

Import the virtual stylesheet once in src/main.jsx:

import 'virtual:registyle.css';

Then use the semantic class in your React component:

import { cx } from 'registyle';

export function Button({ variant = 'primary', className, ...props }) {
  return (
    <button
      className={cx('action-button', `action-button-${variant}`, className)}
      {...props}
    />
  );
}

Run the app as usual:

npm run dev

The CSS flow is handled by Vite: it watches src/registyles, recompiles when a registration changes, and emits CSS during npm run build. The component demo in examples/register-component-demo shows the complete setup.

Writing Utilities

A tw value can be a string or an array of strings. Use a string for a short set of utilities and an array to keep longer sets readable:

register('action-button', {
  tw: [
    'inline-flex items-center rounded-md',
    'bg-blue-600 px-4 py-2 font-medium text-white',
    'hover:(bg-blue-700 text-white)',
  ],
});

Grouped prefixes expand at compile time:

max-sm:(w-full flex-col) -> max-sm:w-full max-sm:flex-col
border-(2 red-500)       -> border-2 border-red-500

Native Tailwind v4 single-value shorthand such as bg-(--brand) is passed through unchanged. Use Tailwind v4 slash notation for color alpha, for example bg-red-500/50.

Other Build Setups

For bundlers without a Registyle plugin, compile a manifest in a Node build script and import the generated CSS through your app's normal CSS pipeline:

// scripts/build-styles.mjs
import { compileToFile } from 'registyle/compile';

const manifest = {
  classes: {
    'action-button': {
      tw: 'inline-flex rounded-md bg-blue-600 px-4 py-2 text-white',
    },
  },
};

await compileToFile(manifest, 'src/registyle.css');

Run node scripts/build-styles.mjs before your framework's build command, then import src/registyle.css from your app entry. If you use a custom Tailwind theme or CSS-first plugins, pass an inputCss option that references your app stylesheet:

await compileToFile(manifest, 'src/registyle.css', {
  inputCss: '@reference "./src/app.css"; @import "tailwindcss/utilities.css";',
  baseDir: process.cwd(),
});

See the integration guide for more build and server-rendering options.

CSS-Only Runtime

For plain CSS declarations without Tailwind, import register() from the package root:

import { register } from 'registyle';

register('notice', {
  padding: '0.75rem 1rem',
  color: '#1e3a8a',
  backgroundColor: '#eff6ff',
});

In the browser, the runtime injects a style tag. In Node.js, call register.extractCSS() after importing registration modules to get the registered CSS for server-side extraction. The runtime API does not compile tw utilities.

API and Guides

Why Registyle

Most approaches make you choose: Tailwind's power or clean class names in HTML. Registyle gives you both.

<!-- ❌ CVA + Tailwind — utility strings sprawl in every JSX file -->
<button class="inline-flex items-center justify-center gap-2 font-medium rounded-md
               bg-blue-600 text-white hover:bg-blue-700 focus-visible:outline-2
               focus-visible:outline-blue-600 px-4 py-2 text-sm transition-colors">

<!-- ✅ registyle — semantic names, Tailwind compiled underneath -->
<button class="btn btn-primary btn-md">
registyle CVA + Tailwind twin.macro vanilla-extract
Semantic class names in HTML ✅ .btn .btn-primary ❌ utility strings ❌ hashed ❌ hashed
Tailwind v4 support ✅ native ✅ ❌ ❌
Zero JS runtime ✅ ⚠️ +2 KB CVA ❌ +8–13 KB ✅
Extend / inheritance ✅ built-in ❌ ❌ ❌
CSS output (22 components) ~7 KB gzip ~10–15 KB N/A ~8–12 KB
Active in 2025 ✅ ✅ ⚠️ stale ✅

Bundle Size

The component demo — 22 full UI components — produces:

Raw Gzip
Tailwind v4 base layer (fixed overhead) 27.4 KB ~5.5 KB
Registyle semantic classes (200+ rules) 9.8 KB ~1.9 KB
Keyframes + CSS variables 1.7 KB ~0.7 KB
Total 38.9 KB 7.3 KB

Zero KB of JavaScript runtime overhead. The base layer overhead is fixed — adding more components costs only ~0.09 KB gzip each.

When to Use Registyle

Registyle is for projects that want Tailwind v4 utilities compiled onto semantic class names from an explicit set of registrations. It is especially useful when component markup should stay independent of the utilities that style it. Choose the CSS-only runtime when you only need plain declarations.

Support This Project

If Registyle helps your project, consider buying me a coffee! Your support helps maintain and improve the library.

Contributing

Contributions are welcome. Report bugs and feature requests through GitHub Issues.

License

MIT

Related Packages

tailmantic

Build your own semantic design system with registered Tailwind CSS v4 utilities.

516 1
@suryanshp1/zencss

A CSS-first utility framework with semantic tokens, four themes, accessible reci...

0 0
vite-plugin-css-position

Custom position of vite styles within a vite react app

9,314 5
csszyx

Universal CSS-in-JS for Tailwind CSS with WASM core

10,845 0
@bouquet-ui/design

The headless design system for Bouquet UI built with Jade Garden and Tailwind CS...

2,601 0

Version History

Version Released License
2.1.1 MIT
2.1.0 MIT
2.0.2 MIT
2.0.1 MIT
2.0.0 MIT