API Reference
Reference for tv, createTV, createCN, VariantProps, cn/cx/cnMerge, and configuration types exported by Tailwind Variants.
Condensed reference for tailwind-variants v4.0.2.
import {
tv,
createTV,
cn,
cnMerge,
cx,
twMerge,
twJoin,
clsx,
type VariantProps
} from 'tailwind-variants';Lite build:
import { tv, createTV, createCN, cn, cx } from 'tailwind-variants/lite';Entries
| Entry | Ships |
|---|---|
tailwind-variants | tv, createTV, cn, cnMerge, cx, defaultConfig, plus twMerge, twJoin, clsx. Ships the built-in merge table |
tailwind-variants/merge | twMerge, twJoin, clsx, cn, cx. The merger without the recipe runtime. No tv |
tailwind-variants/config | Everything on the default entry, with twMergeConfig support, plus createTwMerge, extendTailwindMerge, createTailwindMerge, fromTheme, validators, mergeConfigs, getDefaultConfig. Includes the table compiler, so it is the largest entry |
tailwind-variants/lite | tv, createTV, createCN, cn, cx. No table, so it is the smallest entry. Bring your own twMerge |
clsx is also the default export of the default and merge entries, so tailwind-merge and clsx can be aliased to this package. See Migration.
tv
Creates a variant recipe. Returns a callable function plus metadata.
const button = tv(options, config?);
button({ variant: 'primary' }); // => string (no slots)
button({ variant: 'primary' }).base(); // => string (with slots)
button.base; // resolved base string
button.slots; // slot class map
button.variants; // variant definitions
button.variantKeys; // ['variant', 'size', ...]
button.defaultVariants; // { variant: 'primary', ... }
button.compoundVariants; // array
button.compoundSlots; // arrayOptions
type TVOptions = {
extend?: TVReturnType | TVReturnType[];
base?: ClassValue;
slots?: Record<string, ClassValue>;
variants?: Record<string, Record<string, ClassValue>>;
defaultVariants?: Record<string, ClassValue>;
compoundVariants?: Array<Record<string, unknown> & ClassProp>;
compoundSlots?: Array<Record<string, unknown> & ClassProp>;
};| Option | Description |
|---|---|
extend | Merge parent recipes' base, slots, variants, defaults, compounds; non-empty arrays merge left to right |
base | Shared classes for every call |
slots | Named parts; {} enables implicit base slot only |
variants | Variant axes; per-slot objects when using slots |
defaultVariants | Values applied when keys are omitted |
compoundVariants | Extra classes when multiple conditions match |
compoundSlots | Extra classes on specific slots when conditions match |
Config (2nd argument)
// tailwind-variants
type TVConfig = {
twMerge?: boolean | TwMergeFn;
debug?: boolean; // experimental; dev and browser only
};
// tailwind-variants/config
type TVCustomConfig = TVConfig & {
twMergeConfig?: TWMergeConfig;
};debug logs how each invocation resolves; it is stripped from production builds. See Debugging.
twMergeConfig is only supported by tailwind-variants/config. The default entry throws when a recipe is defined with it. See Configuration.
Lite config is { twMerge?: boolean | TwMergeFn } only. A function twMerge is invoked. twMergeConfig and debug are not available on lite.
Call-site props
type ClassProp = {
class?: ClassValue;
className?: ClassValue;
};Pass variant keys plus optional class / className overrides.
createTV
Returns a tv with default config:
import { createTV } from 'tailwind-variants';
const tv = createTV({ twMerge: true });For twMergeConfig, import from the config entry:
import { createTV } from 'tailwind-variants/config';
const tv = createTV({
twMerge: true,
twMergeConfig: { extend: { /* ... */ } }
});On /lite, pass a merge function. createTV does not bind cn. See createCN below.
cn
Concatenate and merge with default config:
cn('px-2', 'px-4'); // => "px-4"
cn('text-sm', { 'font-bold': true }); // => "text-sm font-bold"
cn(); // => "" (never undefined)On the default build, cn returns a string directly. An empty class list yields "". cn follows clsx, so a numeric 0 among other arguments is dropped and a lone 0 is "0". Lite exports a curried cn that joins; prefer createCN when injecting a merger.
createCN
Lite only. Returns a string cn bound to a merge function. createTV does not bind cn:
import { createCN, createTV } from 'tailwind-variants/lite';
import { twMerge } from 'tailwind-merge';
export const tv = createTV({ twMerge });
export const cn = createCN({ twMerge });Without a function, createCN() is cx.
cnMerge
Concatenate with optional per-call config:
cnMerge('px-2', 'px-4')(); // => "px-4"
cnMerge('px-2', 'px-4')({ twMerge: false }); // => "px-2 px-4"Default and config entries only. Not exported from /lite. The config accepts twMerge. twMergeConfig is accepted by cnMerge from tailwind-variants/config.
cx
Lightweight concat without conflict resolution:
cx('text-blue-500', 'text-red-500'); // => "text-blue-500 text-red-500"Available in default and lite builds. Replaces deprecated cnBase. cx normalizes whitespace and keeps a numeric 0.
twMerge, twJoin, clsx
Merge utilities exported from the default and /merge entries:
import { twMerge, twJoin, clsx } from 'tailwind-variants';
// or
import { twMerge, twJoin, clsx } from 'tailwind-variants/merge';
twMerge('px-2', 'px-4'); // => "px-4"
twJoin('a', ['b'], false && 'c'); // => "a b"
clsx('a', 0, { b: true }); // => "a b"twMerge accepts strings and nested arrays, no object syntax. twJoin joins strings and arrays. clsx follows clsx. See Class Resolution.
VariantProps
Extract variant prop types from a recipe:
type Props = VariantProps<typeof button>;
// { variant?: 'primary' | 'secondary' | 'tertiary'; size?: 'sm' | 'md' }Types
| Type | Description |
|---|---|
ClassValue | string | string[] | Record<string, boolean> | null | undefined |
VariantProps<T> | Inferred variant keys from recipe T |
TVReturnType | Return type of tv() — callable + metadata |
TVConfig | Default-entry config: twMerge, debug |
TVCustomConfig | Config-entry config: TVConfig plus twMergeConfig |
TWMergeConfig | Shape of twMergeConfig: { extend, override, cacheSize, prefix } or a full config |
TVLiteConfig | Lite config: { twMerge?: boolean | TwMergeFn } |
TwMergeFn | (classList: string) => string |
Slotted return type
When slots is defined, calling the recipe returns an object of functions:
const { base, title } = alert({ color: 'danger' });
base({ class: 'mt-2' }); // => stringEach slot function accepts class / className and variant overrides scoped to that slot.