tailwind-variants
Typed Tailwind CSS variant API with slots, compound variants, and built-in class-conflict resolution
Repository Health
Technical Analysis
Tailwind Variants is a TypeScript-first variant API for Tailwind CSS that lets you define base styles, variants, compound variants, default variants, and component slots as a single typed configuration object. It layers built-in Tailwind class-conflict resolution on top of the variant system, so composing and overriding classes never produces duplicate or conflicting utility classes.
Framework-agnostic and dependency-light, it is used to build variant-driven design systems and component libraries — including HeroUI’s own component set — where a consistent, type-safe styling API matters across React, Vue, Svelte, or plain JS projects.
What You Get
- A typed
tv()API for defining base styles, variants, compound variants, default variants, and multi-slot components in one config object - Built-in Tailwind class-conflict resolution (via an internal tailwind-merge-compatible engine) on
tv,createTV,cn, andcnMerge - A
/liteentry point that drops conflict resolution for a smaller bundle when merging isn’t needed cx,cn, andcnMergeutility functions for concatenating and optionally merging class names outside oftv()- Full TypeScript inference for variant props, slot names, and compound-variant conditions
Common Use Cases
- Building a variant-driven design system where each component (button, card, input) exposes typed size/color/state props that map to Tailwind classes
- Building multi-part components with slots (e.g. a card with header/body/footer slots) that share variant state across all slots
- Replacing ad hoc
clsx/template-literal class concatenation with a typed, cacheable resolver that also resolves Tailwind class conflicts - Powering component libraries (like HeroUI) that need a consistent styling API across many components and consumers using different bundlers or frameworks
Under The Hood
Architecture
The package is layered: index.ts is a thin public API that wraps internal/tv.ts’s getTailwindVariants factory, which returns the tv/createTV functions. class-resolver.ts’s createClassResolver branches on a resolved.mode of "plain" | "variant" | "slots" into three specialized resolver closures (createPlainResolver, createVariantResolver, createSlotsResolver) that are built lazily on first invocation so constructing a tv() component stays cheap. resolve-options.ts eagerly parses the raw config into a ResolvedOptions descriptor and lazily compiles variants, compound variants, and compound slots on first call via compileResolvedOptions. cache.ts implements a bounded result cache (256-entry limit) keyed by a props fingerprint plus a compound-variants signature, with the very first invocation always skipping the cache to avoid caching cold-start artifacts. tw-merge.ts implements its own tailwind-merge-compatible engine (parse-class-name, class-group-utils, sort-modifiers) rather than depending on the tailwind-merge package at runtime for the default entry point.
Tech Stack
TypeScript 5.6 in strict mode with exactOptionalPropertyTypes enabled. Built via tsup (esbuild-backed) into dual ESM (dist/index.js) and CJS (dist/index.cjs) bundles with generated .d.ts/.d.cts type files, plus separate lite and utils entry points declared through package.json exports. tailwind-merge and tailwindcss are optional peer dependencies (peerDependenciesMeta.optional: true), so the package still works when Tailwind isn’t present at runtime. The repo uses a pnpm workspace with .nvmrc/packageManager pinning, Biome 2.5 for linting instead of ESLint/Prettier, commitlint plus husky to enforce Conventional Commits, and bumpp + conventional-changelog to automate releases.
Code Quality
15 Vitest test files (cn.test.ts, create-tv.test.ts, merge-engine.test.ts, merge-parity.test.ts, tv-compound-slots.test.ts, tv-extend*.test.ts, tv-slots.test.ts, tv-tailwind-merge.test.ts, and more) cover the resolver modes, extension and composition behavior, and merge parity against upstream tailwind-merge semantics. A separate __types__ directory holds compile-time type tests (tsc -p .config/tsconfig.type-tests.json) that assert the public API’s inferred types for the core, slot, variant, and metadata APIs. strict: true plus exactOptionalPropertyTypes catch a class of undefined-vs-missing bugs at compile time. CI (ci.yml) runs alongside a dedicated benchmark.yml workflow that tracks performance regressions via tinybench.
API Design
The public surface is deliberately small — tv, createTV, cn, cx, cnMerge, and defaultConfig — with tv() itself handling plain, variant, and slot-based components based on the shape of the config object passed in, so there’s no separate API to learn per mode. Slots and compound variants are expressed declaratively in the same config rather than requiring separate composition calls, and createTV mirrors tv exactly but pre-bound to custom config, keeping the mental model consistent. The project is documented at tailwind-variants.org with a runnable quick-start in the README and versioned migration guides (v1→v2, v2→v3) for breaking changes.
Used by 19 apps in this directory
magika
Developer Tools · Security
AI-powered file type detection that identifies 200+ content types with ~99% accuracy in milliseconds using a compact deep learning model.
Markdrop
Note Taking
Visual drag-and-drop markdown editor with GitHub-specific blocks, cloud sync, and offline PWA support
Novu
Developer Tools
Open-source communication infrastructure that connects your products and AI agents to every channel your users live on — Inbox, Email, SMS, Push, Chat, and more.
open-pencil
AI Design Tools · Design Tools
An open-source design editor that reads native Figma files, ships a built-in AI assistant with 100+ design tools, and offers real-time serverless collaboration — all without giving up your files.
Open Scouts
AI Agents · Automation
Create automated AI scouts that continuously search the web and send email alerts when they find what you're looking for.
Probo
Automation · Security
Open-source GRC platform for engineering and security teams.
Rill
Analytics · Data Engineering
The fastest BI tool for humans and agents — define metrics, models, and dashboards as code and query them instantly on ClickHouse or DuckDB.
shaper
Analytics · Data Engineering
Build analytics dashboards, reports, and customer-facing analytics by writing pure SQL — powered by DuckDB and designed for self-hosted deployment.
undb
Databases · No Code Platforms
Self-hosted no-code database and BaaS that lets you manage structured data visually with multi-database support, formula fields, and auto-generated OpenAPI endpoints.