A tiny, modular className utility with conditional classes, Tailwind merge, and type-safe variants.
One package to replace three: clsx + tailwind-merge + class-variance-authority
- Zero dependencies - No runtime dependencies
- Tree-shakeable - Import only what you need
- Type-safe - Full TypeScript with excellent inference
- Tiny bundles - Core is just 248B gzipped
npm install @oxog/classix
# or
pnpm add @oxog/classix
# or
yarn add @oxog/classix| Import | Size | Description |
|---|---|---|
@oxog/classix |
248B | cx() conditional classes |
@oxog/classix/merge |
2.0KB | merge(), createMerge() Tailwind merge |
@oxog/classix/tailwind |
1.9KB | cn() merge + conditional combined |
@oxog/classix/variants |
840B | variants(), slots() variant system |
@oxog/classix/full |
2.5KB | All exports combined |
import { cx } from '@oxog/classix';
// Strings
cx('foo', 'bar'); // 'foo bar'
// Conditionals
cx('foo', true && 'bar', false && 'baz'); // 'foo bar'
// Objects
cx({ foo: true, bar: false, baz: 1 }); // 'foo baz'
// Arrays (nested)
cx(['foo', ['bar', ['baz']]]); // 'foo bar baz'
// Mixed
cx('a', { b: true }, ['c', 'd'], null); // 'a b c d'import { cn } from '@oxog/classix/tailwind';
// Last class wins for conflicts
cn('p-4 text-red-500', 'p-8'); // 'text-red-500 p-8'
cn('px-4 py-2', 'p-8'); // 'p-8'
// With conditionals
cn('p-4', isActive && 'bg-blue-500', className);
// Component pattern
function Button({ className, ...props }) {
return (
<button
className={cn('px-4 py-2 rounded font-medium', className)}
{...props}
/>
);
}import { variants, type VariantProps } from '@oxog/classix/variants';
const button = variants({
base: 'inline-flex items-center justify-center rounded-md font-medium',
variants: {
intent: {
primary: 'bg-blue-500 text-white hover:bg-blue-600',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
danger: 'bg-red-500 text-white hover:bg-red-600',
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4',
lg: 'h-12 px-6 text-lg',
},
},
compounds: [
{ intent: 'primary', size: 'lg', class: 'shadow-lg' },
],
defaults: {
intent: 'primary',
size: 'md',
},
});
// Usage
button(); // defaults applied
button({ intent: 'danger', size: 'sm' }); // override
button({ class: 'my-custom' }); // add custom class
// TypeScript inference
type ButtonProps = VariantProps<typeof button>;const button = variants({
base: 'inline-flex items-center justify-center',
variants: {
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4',
lg: 'h-12 px-6',
},
},
responsive: true,
});
// Different sizes at different breakpoints
button({ size: { base: 'sm', md: 'md', lg: 'lg' } });
// => 'inline-flex ... h-8 px-3 text-sm md:h-10 md:px-4 lg:h-12 lg:px-6'import { slots } from '@oxog/classix/variants';
const card = slots({
slots: {
root: 'rounded-xl border bg-white shadow-sm',
header: 'px-6 py-4 border-b',
title: 'text-lg font-semibold',
content: 'px-6 py-4',
footer: 'px-6 py-4 border-t bg-gray-50',
},
variants: {
variant: {
elevated: { root: 'shadow-lg border-0' },
bordered: { root: 'border-2' },
},
},
});
// Returns slot functions
const { root, header, title, content, footer } = card({ variant: 'elevated' });
<div className={root()}>
<div className={header()}>
<h3 className={title()}>Card Title</h3>
</div>
<div className={content()}>Content</div>
<div className={footer('custom-class')}>Footer</div>
</div>import { cx, type ClassValue } from '@oxog/classix';
cx(...inputs: ClassValue[]): stringimport { merge, createMerge, type MergeConfig } from '@oxog/classix/merge';
merge(...inputs: ClassValue[]): string
createMerge(config: MergeConfig): typeof mergeimport { cn } from '@oxog/classix/tailwind';
cn(...inputs: ClassValue[]): string // cx + merge combinedimport { variants, slots, type VariantProps, type SlotProps } from '@oxog/classix/variants';
variants(config): (props?) => string
slots(config): (props?) => Record<string, (className?) => string>import { cx, merge, createMerge, cn, variants, slots } from '@oxog/classix/full';| Feature | classix | clsx | tailwind-merge | cva |
|---|---|---|---|---|
| Conditional classes | ✅ | ✅ | ❌ | ❌ |
| Tailwind merge | ✅ | ❌ | ✅ | ❌ |
| Variants | ✅ | ❌ | ❌ | ✅ |
| Compound variants | ✅ | ❌ | ❌ | ✅ |
| Responsive variants | ✅ | ❌ | ❌ | ❌ |
| Slots system | ✅ | ❌ | ❌ | ❌ |
| Zero deps | ✅ | ✅ | ❌ | ❌ |
| Tree-shakeable | ✅ | ✅ | ✅ | ✅ |
- Node.js >= 18
- TypeScript >= 5.0 (for full type inference)
MIT - Created by Ersin Koc