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

JavaScript
99%
GPL 3.0

homepage

Monitoring · Productivity

33,326

A fast, fully static, and secure self-hosted startpage with Docker service discovery and integrations for over 160 services.

View details
91
Repo Health
86
Technical
71
Dependency
Built with
JavaScript 99%
Updated 6 days ago
TypeScript
97%
MIT

HyperDX

Analytics · Developer Tools · Monitoring

9,963

Open source observability platform that unifies logs, traces, metrics, and session replays on ClickHouse — now the core of ClickStack.

View details
89
Repo Health
83
Technical
64
Dependency
Built with
TypeScript 97%
Updated 6 days ago
TypeScript
66%
MIT

Jitsu

Data Engineering

5,110

Open-source, fully-scriptable data ingestion engine that streams events from web, apps, and APIs to any data warehouse in real time.

View details
89
Repo Health
79
Technical
66
Dependency
Built with
TypeScript 66%
Go 32%
Updated 1 weeks ago
TypeScript
96%
AGPL 3.0

Kan

Project Management

5,825

An open-source, self-hostable Kanban board built as a modern Trello alternative with team workspaces, board permissions, and Trello import.

View details
86
Repo Health
78
Technical
67
Dependency
Built with
TypeScript 96%
Updated 1 weeks ago
TypeScript
99%
MIT

KeystoneJS

CMS · Developer Tools

9,980

The superpowered headless CMS for developers built with GraphQL and React

View details
92
Repo Health
81
Technical
64
Dependency
Built with
TypeScript 99%
Updated 1 weeks ago
TypeScript
98%
Other

Kibana

Analytics · Monitoring

21,338

Your open source window into the Elastic Stack — query, visualize, and act on data stored in Elasticsearch with real-time dashboards, AI-assisted search, and automated alerting.

View details
98
Repo Health
87
Technical
63
Dependency
Built with
TypeScript 98%
Updated 6 days ago
JavaScript
42%
Other

LimeSurvey

Forms Surveys

3,778

The world's most flexible open-source survey platform with 900+ templates, conditional logic, 80+ languages, and full GDPR compliance for any scale.

View details
86
Repo Health
62
Technical
62
Dependency
Built with
JavaScript 42%
PHP 36%
CSS 12%
Updated 6 days ago
TypeScript
98%
MPL 2.0

Logto

Authentication

14,769

Open-source auth infrastructure for SaaS and AI apps with OIDC, SAML, and RBAC

View details
92
Repo Health
83
Technical
63
Dependency
Built with
TypeScript 98%
Updated 1 weeks ago
TypeScript
44%
Other

Magic

AI Agents · Automation · Low Code Platforms

5,055

Magic is an enterprise-grade open-source AI agent platform combining a generalist AI agent, workflow engine, IM, and collaborative office system for running an AI-powered digital workforce.

View details
68
Repo Health
79
Technical
65
Dependency
Built with
TypeScript 44%
PHP 32%
Updated 2 months 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