Feature Comparison
| Feature | better-styled | Tailwind Variants | CVA | Windstitch | classnames |
|---|---|---|---|---|---|
| Variants | ✅ | ✅ | ✅ | ✅ | ❌ |
| Compound Variants | ✅ | ✅ | ✅ | ❌ | ❌ |
| Default Variants | ✅ | ✅ | ✅ | ✅ | ❌ |
| Context Propagation | ✅ | ❌ | ❌ | ❌ | ❌ |
| Compound Components (Slots) | ✅ | ✅ | ❌ | ❌ | ❌ |
| Type Inference | ✅ Automatic | ⚠️ Needs as const | ⚠️ Needs as const | ✅ Automatic | ❌ |
tailwind-merge | ✅ Built-in | ✅ Optional | ❌ Manual | ❌ | ❌ |
| React Native | ✅ | ⚠️ Via NativeWind | ⚠️ Via NativeWind | ⚠️ Via NativeWind | ⚠️ Via NativeWind |
| Function Composition | ✅ | ❌ | ❌ | ❌ | ❌ |
| Zero Config | ✅ | ⚠️ | ✅ | ✅ | ✅ |
| Bundle Size | ~3kB | ~5kB | ~1kB | ~1.4kB | ~0.5kB |
⚠️ Via NativeWind means the library works with React Native only when combined with NativeWind or Uniwind, since they generate class strings that need to be converted to StyleSheet objects.
What Makes better-styled Different
Context Propagation
This is the killer feature. No other library does this.Function Composition
Event handlers from base, variants, and direct props all execute - nothing gets overwritten.React Native: Components vs Class Strings
All variant libraries work with React Native when combined with NativeWind or Uniwind. The difference is in what they output:| Library | Output | React Native |
|---|---|---|
| better-styled | React components | ✅ Works directly with any component |
| Tailwind Variants | Class strings | ⚠️ Need to manually apply to className |
| CVA | Class strings | ⚠️ Need to manually apply to className |
| Windstitch | Class strings | ⚠️ Need to manually apply to className |
| classnames | Class strings | ⚠️ Need to manually apply to className |
Detailed Comparisons
vs Tailwind Variants
Tailwind Variants is excellent for styling, but it’s not a component library.| Aspect | better-styled | Tailwind Variants |
|---|---|---|
| Output | React components | Class strings |
| Context | ✅ Built-in propagation | ❌ Not available |
| Slots | ✅ withSlots() helper | ✅ Slots API |
| TypeScript | ✅ No as const needed | ⚠️ Requires as const |
| React Native | ✅ Direct component support | ⚠️ Via NativeWind (class strings) |
vs CVA (Class Variance Authority)
CVA is minimal and focused on class generation.| Aspect | better-styled | CVA |
|---|---|---|
| Output | React components | Class strings |
| Context | ✅ Built-in propagation | ❌ Not available |
| Compound Components | ✅ withSlots() | ❌ Manual |
| tailwind-merge | ✅ Built-in | ❌ Manual integration |
| React Native | ✅ Direct component support | ⚠️ Via NativeWind (class strings) |
| Bundle Size | ~3kB | ~1kB |
vs Windstitch
Windstitch is a lightweight Stitches-like library for Tailwind.| Aspect | better-styled | Windstitch |
|---|---|---|
| Context | ✅ Built-in propagation | ❌ Not available |
| Compound Variants | ✅ | ❌ |
| Compound Components | ✅ withSlots() | ❌ |
| tailwind-merge | ✅ Built-in | ❌ |
| React Native | ✅ Direct component support | ⚠️ Via NativeWind (class strings) |
vs classnames
classnames is a simple utility for conditionally joining class names.| Aspect | better-styled | classnames |
|---|---|---|
| Purpose | Component styling with variants | Conditional class joining |
| Variants | ✅ Built-in | ❌ Manual logic |
| Context | ✅ Built-in propagation | ❌ Not available |
| TypeScript | ✅ Full inference | ❌ No variant types |
| React Native | ✅ Direct component support | ⚠️ Via NativeWind (class strings) |
| Bundle Size | ~3kB | ~0.5kB |
Migration Examples
From Tailwind Variants
From CVA
From classnames
Summary
| Library | Best For |
|---|---|
| better-styled | Design systems with parent-child relationships, React Native apps, compound components |
| Tailwind Variants | Class generation with slots, projects that need responsive variants |
| CVA | Minimal bundle size, simple class generation |
| Windstitch | Stitches-like API, lightweight styling |
| classnames | Simple conditional class joining without variants |
Get Started
Ready to try better-styled?