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 18 apps in this directory
Bramble
Password Manager · Security · Authentication
Local-first, end-to-end encrypted password manager that syncs your vault directly between your own devices over a private peer-to-peer mesh — no server, no account, no cloud in the middle.
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
ChartBrew
Analytics · Databases
Open-source reporting platform to build live dashboards from SQL, NoSQL, APIs, and SaaS tools with an AI assistant that creates charts from natural language.
Convex Backend
Developer Tools · Databases
Open-source reactive database that lets developers build live-updating apps with pure TypeScript, strong consistency, and real-time subscriptions—no separate API layer required.
Enso
Analytics · Data Engineering · Low Code Platforms
A visual and textual programming platform for data prep and analysis where the node graph and the underlying Enso code are always perfectly in sync, built by an Alteryx co-founder on a GraalVM engine.
Epicenter
Knowledge Management · Note Taking · Developer Tools
A local-first monorepo led by Whispering, an open-source speech-to-text app, built on an MIT toolkit that turns your data into plain Markdown and SQLite files you own instead of a database you rent.
evidence
Analytics · Data Engineering
Turn SQL queries and markdown files into polished, interactive data apps and business intelligence reports — no drag-and-drop, no GUI, just code.
Keep
Devops · Automation · Monitoring
The open-source AIOps and alert management platform that unifies 130+ monitoring tools into a single pane of glass with AI-powered correlation, deduplication, and workflow automation.
Kener
Monitoring · Devops
Stunning, self-hosted status pages with real-time uptime monitoring, incident management, and multi-channel notifications in a single Docker container.