Skip to content

A tiny, modular className utility with conditional classes, Tailwind merge, and type-safe variants.

License

Notifications You must be signed in to change notification settings

ersinkoc/Classix

Repository files navigation

@oxog/classix

A tiny, modular className utility with conditional classes, Tailwind merge, and type-safe variants.

npm version npm bundle size TypeScript License: MIT

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/classix

Bundle 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[]): string

Merge

import { merge, createMerge, type MergeConfig } from '@oxog/classix/merge';

merge(...inputs: ClassValue[]): string
createMerge(config: MergeConfig): typeof merge

Tailwind

import { cn } from '@oxog/classix/tailwind';

cn(...inputs: ClassValue[]): string  // cx + merge combined

Variants

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

Links

About

A tiny, modular className utility with conditional classes, Tailwind merge, and type-safe variants.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published