@oxog/classix
v1.0.0
Published
A tiny, modular className utility with conditional classes, Tailwind merge, and type-safe variants
Maintainers
Readme
@oxog/classix
A tiny, modular className utility with conditional classes, Tailwind merge, and type-safe variants.
Why classix?
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
Installation
npm install @oxog/classix
# or
pnpm add @oxog/classix
# or
yarn add @oxog/classixBundle Sizes (gzipped)
| 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 |
Quick Start
1. Conditional Classes (cx)
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'2. Tailwind Merge (merge, cn)
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}
/>
);
}3. Type-Safe Variants (variants)
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>;4. Responsive Variants (Unique Feature!)
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'5. Slot-Based Variants (Unique Feature!)
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>API Reference
Core
import { cx, type ClassValue } from '@oxog/classix';
cx(...inputs: ClassValue[]): stringMerge
import { merge, createMerge, type MergeConfig } from '@oxog/classix/merge';
merge(...inputs: ClassValue[]): string
createMerge(config: MergeConfig): typeof mergeTailwind
import { cn } from '@oxog/classix/tailwind';
cn(...inputs: ClassValue[]): string // cx + merge combinedVariants
import { variants, slots, type VariantProps, type SlotProps } from '@oxog/classix/variants';
variants(config): (props?) => string
slots(config): (props?) => Record<string, (className?) => string>Full Bundle
import { cx, merge, createMerge, cn, variants, slots } from '@oxog/classix/full';Comparison
| Feature | classix | clsx | tailwind-merge | cva | |---------|---------|------|----------------|-----| | Conditional classes | ✅ | ✅ | ❌ | ❌ | | Tailwind merge | ✅ | ❌ | ✅ | ❌ | | Variants | ✅ | ❌ | ❌ | ✅ | | Compound variants | ✅ | ❌ | ❌ | ✅ | | Responsive variants | ✅ | ❌ | ❌ | ❌ | | Slots system | ✅ | ❌ | ❌ | ❌ | | Zero deps | ✅ | ✅ | ❌ | ❌ | | Tree-shakeable | ✅ | ✅ | ✅ | ✅ |
Requirements
- Node.js >= 18
- TypeScript >= 5.0 (for full type inference)
Documentation
License
MIT - Created by Ersin Koc
