classnames

A tiny utility for conditionally joining CSS class names together.

Library
npm
v2.5.1
17,770 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
56 /100 Fair
Development Activity 56
Maintenance 8
Community 60
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
87 /100 Excellent
Architecture 82
Code Quality 88
Innovation 85
Learning Curve 92

classnames is a lightweight JavaScript utility, ubiquitous in the React ecosystem, that merges strings, objects, and arrays into a single space-separated className string. Instead of hand-building conditional className logic with ternaries and string concatenation, developers pass truthy/falsy flags as a plain object and let classnames decide which class names survive.

With zero runtime dependencies and a footprint of well under 1KB, it has become a de facto standard for building dynamic UI class lists in component-based frameworks, and ships bind and dedupe variants for CSS Modules and dedup-sensitive use cases respectively.

What You Get

  • Zero-dependency, sub-1KB core classNames() function for conditional class joining
  • classnames/bind variant pre-bound to a CSS Modules style map via a cx() helper
  • classnames/dedupe variant that removes duplicate and overridden class names
  • Full TypeScript type definitions shipped inline (index.d.ts, bind.d.ts, dedupe.d.ts)
  • ESM-only package with sideEffects: false for optimal tree-shaking

Common Use Cases

  • Toggling a CSS class based on component state (e.g. isActive, isPressed, isHovered)
  • Merging a consumer-supplied className prop with a component’s own base classes
  • Building dynamic utility-class strings from multiple conditional sources
  • Binding to CSS Modules style objects to reference local class names instead of raw strings

Under The Hood

Architecture classnames is deliberately minimal: three independent entry points (index.js, bind.js, dedupe.js) share the same conceptual pipeline of recursively flattening arguments (string, object, or array) into class names, but each swaps its accumulation strategy for a different goal. The default build concatenates into a string as it goes; bind.js layers a this-bound lookup so cx() can translate logical names into CSS Modules’ hashed class names; dedupe.js instead accumulates into a null-prototype StorageObject keyed by class name so later truthy/falsy values naturally overwrite earlier ones, producing de-duplicated output at roughly 5x the cost of the default. Module boundaries are exposed cleanly via package.json exports subpaths rather than a single monolithic API.

Tech Stack The package itself has zero runtime dependencies and ships as pure ESM ("type": "module") with sideEffects: false for tree-shaking. Its devDependency set is entirely tooling: Rollup for browser benchmark bundling, tsd for asserting the shipped .d.ts files against real usage, and tinybench/http-server for the in-repo benchmark suite that runs in CI. TypeScript types are hand-written and versioned alongside the JS, not generated.

Code Quality The tests/ directory covers all three entry points (index.js, bind.js, dedupe.js) plus .test-d.ts type-assertion files, using Node’s built-in node:test runner — no external test framework dependency. Coverage is thorough for a small library: truthy/falsy edge cases (NaN, -0, empty string, empty object/array), deep array recursion, custom/inherited toString() overrides, and even execution inside a Node vm context to catch cross-realm bugs. CI (.github/workflows/node.js.yml) runs the test suite across Node 18/20/21, type-checks the .d.ts files, and runs the benchmark suite on every push and PR — there is no separate ESLint/Prettier config in the repo, so style consistency relies on convention rather than tooling.

API Design The public API is a single variadic function call that accepts strings, objects, arrays, or any mix thereof, which removes essentially all boilerplate compared to manual ternary/string-concatenation class building. Argument handling is intuitive and well documented in the README with realistic React examples. The bind and dedupe variants reuse the exact same calling convention as the default export, so switching between them is a one-line import change with no API relearning. The main friction point is the ESM-only, type: module packaging, which is a minor breaking change for consumers still on CommonJS-only tooling.

Used by 68 apps in this directory

TypeScript
96%
Other

Refly

AI Development · Automation · No Code Platforms

7,537

Build deterministic, versioned agent skills from natural language—run them anywhere from Claude Code to Slack.

View details
68
Repo Health
76
Technical
63
Dependency
Built with
TypeScript 96%
Updated 1 weeks ago
TypeScript
97%
AGPL 3.0

Responsively App

Design Tools · Developer Tools

25,464

Preview and interact with your responsive web design across every device size simultaneously — no more manual resizing.

View details
79
Repo Health
71
Technical
66
Dependency
Built with
TypeScript 97%
Updated 4 weeks ago
Python
76%
Apache 2.0

Second Me

AI Assistants · Productivity

15,687

Train a locally hosted AI twin on your own memories—then connect it to the world through a decentralized identity network.

View details
41
Repo Health
75
Technical
68
Dependency
Built with
Python 76%
TypeScript 19%
Updated 1 years ago
Python
57%
Other

Sentry

Analytics · Developer Tools · Monitoring

45,632

Developer-first error tracking and performance monitoring platform with AI-powered root-cause analysis across 20+ languages and frameworks.

View details
95
Repo Health
80
Technical
66
Dependency
Built with
Python 57%
TypeScript 42%
Updated 1 weeks ago
TypeScript
50%
Other

SigNoz

Analytics · Monitoring

32,429

Self-host your entire observability stack — logs, metrics, traces, and LLM monitoring — in one OpenTelemetry-native platform, without the Datadog bill.

View details
92
Repo Health
83
Technical
64
Dependency
Built with
TypeScript 50%
Go 38%
Updated 1 weeks ago
Go
66%
GPL 3.0

Stormkit

Devops · Hosting Control Panel

264

Self-hostable platform for deploying and hosting modern web apps with automated CI/CD, custom domains, and a built-in serverless runtime — a true open-source alternative to Vercel and Netlify.

View details
80
Repo Health
79
Technical
67
Dependency
Built with
Go 66%
TypeScript 31%
Updated 1 weeks ago
TypeScript
72%
Apache 2.0

Supabase

Authentication · Databases · Developer Tools

113,827

The open-source Postgres development platform that replaces Firebase with authentication, real-time APIs, edge functions, storage, and vector embeddings — all built on PostgreSQL.

View details
90
Repo Health
91
Technical
62
Dependency
Built with
TypeScript 72%
MDX 26%
Updated 1 weeks ago
JavaScript
93%
Apache 2.0

swagger-ui

Developer Tools

29,042

Transform OpenAPI specifications into interactive, browser-based API documentation that developers and consumers can explore and test live.

View details
98
Repo Health
83
Technical
62
Dependency
Built with
JavaScript 93%
Updated 1 weeks ago
HTML
68%
AGPL 3.0

ToolJet

AI Agents · Low Code Platforms · No Code Platforms

41,123

Open-source AI-native platform to build and deploy internal tools, workflows, and AI agents with a visual drag-and-drop builder and 80+ data source integrations.

View details
94
Repo Health
81
Technical
63
Dependency
Built with
HTML 68%
JavaScript 20%
Updated 1 weeks ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers