Skip to content

Commit 1683e14

Browse files
committed
docs(benchmark): add detailed benchmark documentation and reorganize suite
- Add benchmarks.mdx page with comprehensive performance comparison tables - Reorganize benchmark files into cv-vs-cva, cv-vs-tv, and scv-vs-tv-slots folders - Extract shared configs into reusable modules (cv, cva, tv, scv, tv-slots) - Add README documenting benchmark methodology and folder structure - Update performance.mdx to link to new benchmarks page - Rename bench script to start in package.json
1 parent f221a66 commit 1683e14

25 files changed

Lines changed: 2285 additions & 1525 deletions

apps/docs/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export default defineConfig({
9494
{ label: 'Migration from CVA', slug: 'resources/migration-cva' },
9595
{ label: 'Migration from Tailwind Variants', slug: 'resources/migration-tailwind-variants' },
9696
{ label: 'Performance', slug: 'resources/performance' },
97+
{ label: 'Benchmarks', slug: 'resources/benchmarks' },
9798
{ label: 'FAQ', slug: 'resources/faq' },
9899
],
99100
},
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
title: Benchmarks
3+
description: Detailed performance comparison of css-variants against class-variance-authority and tailwind-variants
4+
---
5+
6+
import { Card, CardGrid, Aside, Badge, Tabs, TabItem } from '@astrojs/starlight/components';
7+
8+
Performance matters. css-variants is engineered for speed, delivering exceptional runtime performance without sacrificing features.
9+
10+
## Quick Summary
11+
12+
| Comparison | Simple Ops | Compound Variants | Complex Components | Slots |
13+
|:-----------|:----------:|:-----------------:|:------------------:|:-----:|
14+
| **vs cva** | ~1.1-1.3x | **3-4x faster** | **2-7x faster** ||
15+
| **vs tailwind-variants** | **3-5x faster** | **5-7x faster** | **10-11x faster** | **3-7x faster** |
16+
17+
<Aside type="tip" title="Performance scales with complexity">
18+
The more complex your components, the bigger the performance advantage. Real-world production components with multiple variants and compound rules see the most dramatic improvements.
19+
</Aside>
20+
21+
---
22+
23+
## css-variants vs class-variance-authority
24+
25+
Direct comparison against the popular [class-variance-authority](https://cva.style) (cva) library.
26+
27+
### Basic Operations
28+
29+
| Test Case | css-variants | cva | Difference |
30+
|-----------|-------------:|----:|:-----------|
31+
| Base class only | 23.2M ops/s | 21.2M ops/s | **1.09x faster** |
32+
| Single variant | 9.4M ops/s | 9.4M ops/s | Equal |
33+
| Multiple variants | 5.1M ops/s | 4.7M ops/s | **1.07x faster** |
34+
| Boolean variants | 5.9M ops/s | 5.0M ops/s | **1.18x faster** |
35+
| className override | 20.7M ops/s | 15.7M ops/s | **1.31x faster** |
36+
37+
### Default Variants
38+
39+
| Test Case | css-variants | cva | Difference |
40+
|-----------|-------------:|----:|:-----------|
41+
| Defaults (no props) | 9.3M ops/s | 8.0M ops/s | **1.16x faster** |
42+
| Override one default | 8.2M ops/s | 6.3M ops/s | **1.31x faster** |
43+
| With className | 8.4M ops/s | 6.6M ops/s | **1.27x faster** |
44+
45+
### Compound Variants
46+
47+
This is where css-variants really shines:
48+
49+
| Test Case | css-variants | cva | Difference |
50+
|-----------|-------------:|----:|:-----------|
51+
| No match | 4.2M ops/s | 1.1M ops/s | **3.70x faster** |
52+
| Single match | 4.1M ops/s | 1.0M ops/s | **3.92x faster** |
53+
| Multiple matches | 3.8M ops/s | 0.9M ops/s | **4.24x faster** |
54+
55+
<Aside type="tip" title="Why compound variants are faster">
56+
css-variants uses optimized iteration and early-exit strategies when checking compound variant conditions, resulting in significantly better performance as complexity increases.
57+
</Aside>
58+
59+
### Complex Real-World Components
60+
61+
Testing a production-ready button component with 6 variant options and compound rules:
62+
63+
| Test Case | css-variants | cva | Difference |
64+
|-----------|-------------:|----:|:-----------|
65+
| With defaults | 8.1M ops/s | 3.4M ops/s | **2.40x faster** |
66+
| With overrides | 5.1M ops/s | 0.7M ops/s | **6.93x faster** |
67+
68+
---
69+
70+
## css-variants vs tailwind-variants
71+
72+
Comparison against [tailwind-variants](https://www.tailwind-variants.org/), using its lightweight `/lite` build.
73+
74+
### Basic Operations
75+
76+
| Test Case | css-variants | tailwind-variants | Difference |
77+
|-----------|-------------:|------------------:|:-----------|
78+
| Base class only | 23.1M ops/s | 6.4M ops/s | **3.59x faster** |
79+
| Single variant | 9.9M ops/s | 2.2M ops/s | **4.52x faster** |
80+
| Multiple variants | 4.8M ops/s | 1.1M ops/s | **4.58x faster** |
81+
| Boolean variants | 5.8M ops/s | 1.6M ops/s | **3.57x faster** |
82+
| className override | 21.4M ops/s | 3.9M ops/s | **5.47x faster** |
83+
84+
### Default Variants
85+
86+
| Test Case | css-variants | tailwind-variants | Difference |
87+
|-----------|-------------:|------------------:|:-----------|
88+
| Defaults (no props) | 8.6M ops/s | 1.4M ops/s | **6.04x faster** |
89+
| Override one default | 8.6M ops/s | 1.4M ops/s | **6.35x faster** |
90+
| With className | 8.4M ops/s | 2.1M ops/s | **4.07x faster** |
91+
92+
### Compound Variants
93+
94+
| Test Case | css-variants | tailwind-variants | Difference |
95+
|-----------|-------------:|------------------:|:-----------|
96+
| No match | 4.2M ops/s | 0.6M ops/s | **6.60x faster** |
97+
| Single match | 4.0M ops/s | 0.7M ops/s | **5.43x faster** |
98+
| Multiple matches | 3.8M ops/s | 0.7M ops/s | **5.57x faster** |
99+
100+
### Complex Real-World Components
101+
102+
| Test Case | css-variants | tailwind-variants | Difference |
103+
|-----------|-------------:|------------------:|:-----------|
104+
| With defaults | 8.1M ops/s | 0.8M ops/s | **10.39x faster** |
105+
| With overrides | 5.2M ops/s | 0.5M ops/s | **11.05x faster** |
106+
107+
---
108+
109+
## Slot-Based Components: scv vs tailwind-variants
110+
111+
Comparing css-variants' `scv` (slot class variants) against tailwind-variants' slots feature.
112+
113+
### Basic Slots
114+
115+
| Test Case | css-variants (scv) | tailwind-variants | Difference |
116+
|-----------|-------------------:|------------------:|:-----------|
117+
| Base slots (2 slots) | 11.4M ops/s | 2.1M ops/s | **5.33x faster** |
118+
| Single variant (2 slots) | 3.9M ops/s | 1.2M ops/s | **3.25x faster** |
119+
| Multiple slots (4 slots) | 2.2M ops/s | 0.6M ops/s | **3.79x faster** |
120+
| Multiple variants (4 slots) | 1.8M ops/s | 0.4M ops/s | **4.67x faster** |
121+
| No variants (optimized) | 9.3M ops/s | 2.0M ops/s | **4.59x faster** |
122+
123+
### Default Variants with Slots
124+
125+
| Test Case | css-variants (scv) | tailwind-variants | Difference |
126+
|-----------|-------------------:|------------------:|:-----------|
127+
| Defaults (no props) | 2.8M ops/s | 0.7M ops/s | **3.95x faster** |
128+
| Override one default | 2.7M ops/s | 0.8M ops/s | **3.52x faster** |
129+
| With classNames | 2.8M ops/s | 1.0M ops/s | **2.75x faster** |
130+
131+
### Compound Variants with Slots
132+
133+
| Test Case | css-variants (scv) | tailwind-variants | Difference |
134+
|-----------|-------------------:|------------------:|:-----------|
135+
| No match | 1.8M ops/s | 0.3M ops/s | **6.04x faster** |
136+
| Single match | 1.7M ops/s | 0.2M ops/s | **7.45x faster** |
137+
| Multiple matches | 1.6M ops/s | 0.2M ops/s | **7.47x faster** |
138+
139+
### Complex Slot Components
140+
141+
| Test Case | css-variants (scv) | tailwind-variants | Difference |
142+
|-----------|-------------------:|------------------:|:-----------|
143+
| Card (7 slots, defaults) | 1.6M ops/s | 0.3M ops/s | **6.26x faster** |
144+
| Card (7 slots, overrides) | 0.8M ops/s | 0.1M ops/s | **7.32x faster** |
145+
| Stress test (8 slots) | 1.2M ops/s | 0.3M ops/s | **3.44x faster** |
146+
147+
<Aside type="note" title="API Design Impact">
148+
tailwind-variants returns slot functions that must be called individually, adding overhead per slot. css-variants returns pre-computed strings for all slots in a single call, making it fundamentally more efficient.
149+
</Aside>
150+
151+
---
152+
153+
## Why css-variants is Faster
154+
155+
### 1. Optimized Data Structures
156+
157+
css-variants uses simple JavaScript objects and arrays with minimal indirection. No complex class instances or prototype chains.
158+
159+
### 2. Early Exit Strategies
160+
161+
When checking compound variants, css-variants exits as soon as a mismatch is found, avoiding unnecessary comparisons.
162+
163+
### 3. Pre-computation
164+
165+
Variant configurations are analyzed at creation time, not at runtime. The returned function is optimized for the specific configuration.
166+
167+
### 4. Minimal String Operations
168+
169+
Class strings are concatenated efficiently using a lightweight `cx` utility, avoiding expensive regex operations or repeated string allocations.
170+
171+
### 5. No Runtime Dependencies
172+
173+
Zero external dependencies means no additional function call overhead or module resolution costs.
174+
175+
---
176+
177+
## Running Benchmarks Yourself
178+
179+
Clone the repository and run the benchmarks on your machine:
180+
181+
```bash
182+
git clone https://github.com/timphandev/css-variants.git
183+
cd css-variants
184+
yarn install
185+
cd internal/benchmark
186+
yarn start
187+
```
188+
189+
Results are saved to `internal/benchmark/dist/benchmark.json`.
190+
191+
### Benchmark Configuration
192+
193+
- **Framework**: Vitest Bench (using tinybench)
194+
- **Duration**: 500ms minimum per test
195+
- **Warmup**: Automatic by tinybench
196+
- **Environment**: Node.js
197+
198+
---
199+
200+
## Methodology
201+
202+
All benchmarks follow these principles:
203+
204+
1. **Fair comparison**: Identical configurations for both libraries
205+
2. **Isolated setup**: Variant configs created outside bench blocks (not measured)
206+
3. **Real-world scenarios**: Test cases mirror actual production usage patterns
207+
4. **Statistical rigor**: Multiple iterations with standard deviation and percentile metrics
208+
209+
<Aside type="tip" title="Benchmark Source Code">
210+
View the complete benchmark suite on [GitHub](https://github.com/timphandev/css-variants/tree/main/internal/benchmark).
211+
</Aside>
212+
213+
---
214+
215+
*Last updated: December 2025*

apps/docs/src/content/docs/resources/performance.mdx

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -193,25 +193,7 @@ This makes it ideal for SSR frameworks like Next.js, Nuxt, and Remix.
193193
4. **Import only what you need** for optimal tree-shaking
194194
5. **Memoize only when profiling shows it's needed**
195195

196-
## Benchmark Comparison
197-
198-
css-variants delivers exceptional performance compared to popular alternatives:
199-
200-
| Benchmark | vs cva | vs tailwind-variants |
201-
|-----------|:------:|:--------------------:|
202-
| **Overall** |Faster in 11/13 scenarios |Faster in all scenarios |
203-
| **Compound Variants** | 🚀 **3-4x faster** | 🚀 **5-6x faster** |
204-
| **Complex Components** | 🚀 **4-9x faster** | 🚀 **10-11x faster** |
205-
| **Simple Operations** |Competitive | 🚀 **3-7x faster** |
206-
207-
:::tip[Performance Scales with Complexity]
208-
The more complex your components, the bigger the performance advantage. Real-world production components with multiple variants and compound rules see the most dramatic improvements.
196+
:::tip[Want to see the numbers?]
197+
Check out our [detailed benchmark comparison](/resources/benchmarks) to see how css-variants performs against popular alternatives like class-variance-authority and tailwind-variants.
209198
:::
210199

211-
*Benchmarks last updated: 2025-12-11*
212-
213-
Run `yarn benchmark bench` to regenerate these benchmarks on your machine.
214-
215-
**Benchmark source code:**
216-
- [vs class-variance-authority](https://github.com/timphandev/css-variants/blob/main/internal/benchmark/src/cva/)
217-
- [vs tailwind-variants](https://github.com/timphandev/css-variants/blob/main/internal/benchmark/src/tailwind-variants/)

0 commit comments

Comments
 (0)