First-class variant API for Tailwind CSS that enables developers to create reusable component styles with type-safe variants, slots support, and automatic conflict resolution
—
Tailwind Variants provides comprehensive utility functions for conditional class name construction, object manipulation, and array processing. These utilities support both the main variant system and standalone usage for general-purpose class name manipulation.
Conditional class name utility with optional tailwind-merge integration for automatic conflict resolution.
const cn: <T extends CnOptions>(...classes: T) => (config?: TWMConfig) => CnReturn;Parameters:
...classes - Variable number of class values (strings, numbers, objects, arrays)Returns: Function that accepts optional TWMConfig and returns the processed class string
Usage:
import { cn } from "tailwind-variants";
// Basic usage
const classes = cn("px-4 py-2", "bg-blue-500", "text-white")();
// Returns: "px-4 py-2 bg-blue-500 text-white"
// Conditional classes with objects
const buttonClasses = cn(
"px-4 py-2 rounded",
{
"bg-blue-500": isPrimary,
"bg-red-500": isDanger,
"opacity-50": isDisabled,
}
)();
// With arrays
const classes = cn(
"base-class",
["conditional-class", isActive && "active-class"],
{ "hover:bg-gray-100": !isDisabled }
)();
// With tailwind-merge config
const classes = cn("px-4 px-6", "py-2 py-3")({ twMerge: true });
// Returns: "px-6 py-3" (conflicts resolved)Base class name utility without tailwind-merge integration, providing core conditional class logic.
const cnBase: <T extends CnOptions>(...classes: T) => CnReturn;Parameters:
...classes - Variable number of class values (strings, numbers, objects, arrays)Returns: Processed class string or undefined
Usage:
import { cnBase } from "tailwind-variants";
// Direct class name processing
const classes = cnBase(
"px-4 py-2",
isActive && "bg-blue-500",
{ "text-white": isActive, "text-gray-600": !isActive }
);
// Returns: "px-4 py-2 bg-blue-500 text-white" (if isActive is true)
// With nested arrays
const classes = cnBase([
"base-class",
["nested-class", isNested && "conditional-nested"]
]);Removes extra whitespace and trims strings.
const removeExtraSpaces: (str: string) => string;Parameters:
str - Input string to cleanReturns: String with extra spaces removed and trimmed
Usage:
import { removeExtraSpaces } from "tailwind-variants/utils";
const cleaned = removeExtraSpaces(" px-4 py-2 bg-blue-500 ");
// Returns: "px-4 py-2 bg-blue-500"Converts specific falsy values to their string representations.
const falsyToString: <T>(value: T) => T | string;Parameters:
value - Value to convertReturns: Original value or string representation for false, true, 0
Usage:
import { falsyToString } from "tailwind-variants/utils";
falsyToString(false); // Returns: "false"
falsyToString(true); // Returns: "true"
falsyToString(0); // Returns: "0"
falsyToString("test"); // Returns: "test"Checks if an object is empty or not an object.
const isEmptyObject: (obj: unknown) => boolean;Parameters:
obj - Value to checkReturns: True if empty or not an object, false otherwise
Usage:
import { isEmptyObject } from "tailwind-variants/utils";
isEmptyObject({}); // Returns: true
isEmptyObject({ a: 1 }); // Returns: false
isEmptyObject(null); // Returns: true
isEmptyObject("test"); // Returns: truePerforms shallow equality check for objects.
const isEqual: (obj1: object, obj2: object) => boolean;Parameters:
obj1 - First object to compareobj2 - Second object to compareReturns: True if objects have same keys and values, false otherwise
Usage:
import { isEqual } from "tailwind-variants/utils";
isEqual({ a: 1, b: 2 }, { a: 1, b: 2 }); // Returns: true
isEqual({ a: 1 }, { a: 1, b: 2 }); // Returns: falseChecks if a value is a boolean.
const isBoolean: (value: unknown) => boolean;Parameters:
value - Value to checkReturns: True if value is true or false, false otherwise
Usage:
import { isBoolean } from "tailwind-variants/utils";
isBoolean(true); // Returns: true
isBoolean(false); // Returns: true
isBoolean("true"); // Returns: false
isBoolean(1); // Returns: falseJoins two objects with class value merging using cn.
const joinObjects: <T extends Record<string, unknown>, U extends Record<string, unknown>>(
obj1: T,
obj2: U,
) => T & U;Parameters:
obj1 - First objectobj2 - Second object to mergeReturns: Merged object with class values combined
Usage:
import { joinObjects } from "tailwind-variants/utils";
const obj1 = { class: "px-4 py-2", color: "blue" };
const obj2 = { class: "bg-blue-500", size: "md" };
const merged = joinObjects(obj1, obj2);
// Returns: { class: "px-4 py-2 bg-blue-500", color: "blue", size: "md" }Deep merges two objects with special handling for arrays and strings.
const mergeObjects: <T extends object, U extends object>(
obj1: T,
obj2: U,
) => Record<string, unknown>;Parameters:
obj1 - First objectobj2 - Second object to mergeReturns: Deeply merged object
Usage:
import { mergeObjects } from "tailwind-variants/utils";
const obj1 = {
variants: { size: { sm: "text-sm" } },
classes: ["base-class"]
};
const obj2 = {
variants: { size: { md: "text-base" }, color: { primary: "bg-blue-500" } },
classes: ["additional-class"]
};
const merged = mergeObjects(obj1, obj2);
// Returns merged object with combined variants and flattened arraysRecursively flattens array into a target array.
const flat: <T>(arr: unknown[], target: T[]) => void;Parameters:
arr - Array to flattentarget - Target array to populateReturns: Void (modifies target array)
Usage:
import { flat } from "tailwind-variants/utils";
const nested = ["a", ["b", ["c", "d"]], "e"];
const target: string[] = [];
flat(nested, target);
// target now contains: ["a", "b", "c", "d", "e"]Flattens nested arrays.
const flatArray: <T>(array: unknown[]) => T[];Parameters:
array - Array to flattenReturns: Flattened array
Usage:
import { flatArray } from "tailwind-variants/utils";
const nested = ["a", ["b", ["c", "d"]], "e"];
const flattened = flatArray<string>(nested);
// Returns: ["a", "b", "c", "d", "e"]Flattens and merges multiple arrays, filtering out falsy values.
const flatMergeArrays: <T>(...arrays: unknown[][]) => T[];Parameters:
...arrays - Multiple arrays to flatten and mergeReturns: Flattened and filtered array
Usage:
import { flatMergeArrays } from "tailwind-variants/utils";
const result = flatMergeArrays<string>(
["a", ["b"]],
["c", null, "d"],
[["e", false, "f"]]
);
// Returns: ["a", "b", "c", "d", "e", "f"] (falsy values filtered out)const flatMergeArrays: <T>(...arrays: unknown[][]) => T[];Parameters:
...arrays - Multiple arrays to flatten and mergeReturns: Flattened and filtered array
Usage:
import { flatMergeArrays } from "tailwind-variants/utils";
const result = flatMergeArrays<string>(
["a", ["b"]],
["c", null, "d"],
[["e", false, "f"]]
);
// Returns: ["a", "b", "c", "d", "e", "f"] (falsy values filtered out)Extracts variant prop types from a TV component for use in component interfaces.
type VariantProps<Component extends (...args: any) => any> = Omit<
OmitUndefined<Parameters<Component>[0]>,
"class" | "className"
>;Parameters:
Component - A TV component functionReturns: Type representing the variant props without class/className
Usage:
import { tv, VariantProps } from "tailwind-variants";
const button = tv({
base: "font-medium rounded-lg",
variants: {
color: {
primary: "bg-blue-500 text-white",
secondary: "bg-gray-500 text-white",
},
size: {
sm: "px-3 py-1.5 text-sm",
md: "px-4 py-2 text-base",
},
},
});
// Extract props type for React component
type ButtonProps = VariantProps<typeof button> & {
children: React.ReactNode;
};
// Results in: { color?: "primary" | "secondary"; size?: "sm" | "md"; children: React.ReactNode; }
function Button({ color, size, children, ...props }: ButtonProps) {
return (
<button className={button({ color, size })} {...props}>
{children}
</button>
);
}type CnClassValue =
| string
| number
| bigint
| boolean
| null
| undefined
| CnClassDictionary
| CnClassArray;
interface CnClassDictionary {
[key: string]: any;
}
interface CnClassArray extends Array<CnClassValue> {}
type CnOptions = CnClassValue[];
type CnReturn = string | undefined;
interface TWMConfig {
twMerge?: boolean;
twMergeConfig?: TWMergeConfig;
}
type OmitUndefined<T> = T extends undefined ? never : T;
type StringToBoolean<T> = T extends "true" | "false" ? boolean : T;Install with Tessl CLI
npx tessl i tessl/npm-tailwind-variants