{"id":13396614,"url":"https://github.com/JedWatson/classnames","last_synced_at":"2025-03-13T23:31:34.453Z","repository":{"id":22848415,"uuid":"26195776","full_name":"JedWatson/classnames","owner":"JedWatson","description":"A simple javascript utility for conditionally joining classNames together","archived":false,"fork":false,"pushed_at":"2024-04-11T11:56:02.000Z","size":771,"stargazers_count":17341,"open_issues_count":4,"forks_count":552,"subscribers_count":124,"default_branch":"main","last_synced_at":"2024-04-11T17:18:15.266Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JedWatson.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2014-11-05T00:44:31.000Z","updated_at":"2024-04-15T05:09:02.898Z","dependencies_parsed_at":"2022-07-09T10:00:18.529Z","dependency_job_id":"12522319-f2fd-4222-9d87-dbfc3b1efd68","html_url":"https://github.com/JedWatson/classnames","commit_stats":{"total_commits":264,"total_committers":51,"mean_commits":5.176470588235294,"dds":0.6590909090909092,"last_synced_commit":"d52250f1c216df531c556d4ed0831d665e5c0569"},"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JedWatson%2Fclassnames","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JedWatson%2Fclassnames/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JedWatson%2Fclassnames/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JedWatson%2Fclassnames/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JedWatson","download_url":"https://codeload.github.com/JedWatson/classnames/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221421578,"owners_count":16817836,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T18:00:58.114Z","updated_at":"2024-10-25T11:31:00.827Z","avatar_url":"https://github.com/JedWatson.png","language":"JavaScript","readme":"# Classnames\n\n\u003e A simple JavaScript utility for conditionally joining classNames together.\n\n\u003cp\u003e\n  \u003ca aria-label=\"NPM version\" href=\"https://www.npmjs.com/package/classnames\"\u003e\n    \u003cimg alt=\"\" src=\"https://img.shields.io/npm/v/classnames.svg?style=for-the-badge\u0026labelColor=0869B8\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"License\" href=\"#\"\u003e\n    \u003cimg alt=\"\" src=\"https://img.shields.io/npm/l/classnames.svg?style=for-the-badge\u0026labelColor=579805\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Thinkmill Logo\" href=\"https://www.thinkmill.com.au/open-source?utm_campaign=github-classnames\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Sponsored%20BY%20Thinkmill-ed0000.svg?style=for-the-badge\u0026logo=data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTg2IiBoZWlnaHQ9IjU4NiIgdmlld0JveD0iMCAwIDU4NiA1ODYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xOTk2XzQwNikiPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTU4NiAyOTNDNTg2IDQ1NC44MTkgNDU0LjgxOSA1ODYgMjkzIDU4NkMxMzEuMTgxIDU4NiAwIDQ1NC44MTkgMCAyOTNDMCAxMzEuMTgxIDEzMS4xODEgMCAyOTMgMEM0NTQuODE5IDAgNTg2IDEzMS4xODEgNTg2IDI5M1pNMjA1Ljc3NiAzNTguOTQ0QzE5MS4zNzYgMzU4Ljk0NCAxODUuOTA0IDM1Mi4zMiAxODUuOTA0IDMzNS45MDRWMjYyLjc1MkgyMTQuNDE2VjIzNy42OTZIMTg1LjkwNFYyMDEuMTJIMTUzLjA3MlYyMzcuNjk2SDEyOC41OTJWMjYyLjc1MkgxNTMuMDcyVjM0MC44QzE1My4wNzIgMzcyLjc2OCAxNjYuNjA4IDM4NS43MjggMTk3LjQyNCAzODUuNzI4QzIwMy40NzIgMzg1LjcyOCAyMTAuOTYgMzg0LjU3NiAyMTUuODU2IDM4My4xMzZWMzU3LjUwNEMyMTMuNTUyIDM1OC4zNjggMjA5LjUyIDM1OC45NDQgMjA1Ljc3NiAzNTguOTQ0Wk00MDcuMzc2IDIzNC4yNEMzODUuMiAyMzQuMjQgMzcxLjA4OCAyNDQuMDMyIDM2MC40MzIgMjYwLjczNkMzNTIuOTQ0IDI0My40NTYgMzM3LjM5MiAyMzQuMjQgMzE3LjIzMiAyMzQuMjRDMjk5Ljk1MiAyMzQuMjQgMjg2Ljk5MiAyNDEuMTUyIDI3Ni42MjQgMjU1LjI2NEgyNzYuMDQ4VjIzNy42OTZIMjQ0LjY1NlYzODRIMjc3LjQ4OFYzMDUuNjY0QzI3Ny40ODggMjc3LjQ0IDI4OC43MiAyNjAuNzM2IDMwOC4zMDQgMjYwLjczNkMzMjUuMjk2IDI2MC43MzYgMzM0LjUxMiAyNzIuODMyIDMzNC41MTIgMjkzLjU2OFYzODRIMzY3LjM0NFYzMDUuMDg4QzM2Ny4zNDQgMjc3LjE1MiAzNzguODY0IDI2MC43MzYgMzk4LjE2IDI2MC43MzZDNDE0LjU3NiAyNjAuNzM2IDQyNC42NTYgMjcxLjEwNCA0MjQuNjU2IDI5Ny4wMjRWMzg0SDQ1Ny40ODhWMjkzLjg1NkM0NTcuNDg4IDI1NC40IDQzOC40OCAyMzQuMjQgNDA3LjM3NiAyMzQuMjRaIiBmaWxsPSJ3aGl0ZSIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzE5OTZfNDA2Ij4KPHJlY3Qgd2lkdGg9IjU4NiIgaGVpZ2h0PSI1ODYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==\u0026labelColor=C60200\u0026locoColor=white\u0026logoWidth=0\"\u003e\n  \u003c/a\u003e\n\n  \u003c/p\u003e\n\nInstall from the [npm registry](https://www.npmjs.com/) with your package manager:\n```bash\nnpm install classnames\n```\n\nUse with [Node.js](https://nodejs.org/en/), [Browserify](https://browserify.org/), or [webpack](https://webpack.github.io/):\n\n```js\nconst classNames = require('classnames');\nclassNames('foo', 'bar'); // =\u003e 'foo bar'\n```\n\nAlternatively, you can simply include `index.js` on your page with a standalone `\u003cscript\u003e` tag and it will export a global `classNames` method, or define the module if you are using RequireJS.\n\n### Project philosophy\n\nWe take the stability and performance of this package seriously, because it is run millions of times a day in browsers all around the world. Updates are thoroughly reviewed for performance implications before being released, and we have a comprehensive test suite.\n\nClassnames follows the [SemVer](https://semver.org/) standard for versioning.\n\nThere is also a [Changelog](https://github.com/JedWatson/classnames/blob/master/HISTORY.md).\n\n## Usage\n\nThe `classNames` function takes any number of arguments which can be a string or object.\nThe argument `'foo'` is short for `{ foo: true }`. If the value associated with a given key is falsy, that key won't be included in the output.\n\n```js\nclassNames('foo', 'bar'); // =\u003e 'foo bar'\nclassNames('foo', { bar: true }); // =\u003e 'foo bar'\nclassNames({ 'foo-bar': true }); // =\u003e 'foo-bar'\nclassNames({ 'foo-bar': false }); // =\u003e ''\nclassNames({ foo: true }, { bar: true }); // =\u003e 'foo bar'\nclassNames({ foo: true, bar: true }); // =\u003e 'foo bar'\n\n// lots of arguments of various types\nclassNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // =\u003e 'foo bar baz quux'\n\n// other falsy values are just ignored\nclassNames(null, false, 'bar', undefined, 0, { baz: null }, ''); // =\u003e 'bar'\n```\n\nArrays will be recursively flattened as per the rules above:\n\n```js\nconst arr = ['b', { c: true, d: false }];\nclassNames('a', arr); // =\u003e 'a b c'\n```\n\n### Dynamic class names with ES2015\n\nIf you're in an environment that supports [computed keys](https://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer) (available in ES2015 and Babel) you can use dynamic class names:\n\n```js\nconst buttonType = 'primary';\nclassNames({ [`btn-${buttonType}`]: true });\n```\n\n### Usage with React.js\n\nThis package is the official replacement for `classSet`, which was originally shipped in the React.js Addons bundle.\n\nOne of its primary use cases is to make dynamic and conditional `className` props simpler to work with (especially more so than conditional string manipulation). So where you may have the following code to generate a `className` prop for a `\u003cbutton\u003e` in React:\n\n```js\nimport React, { useState } from 'react';\n\nexport default function Button (props) {\n  const [isPressed, setIsPressed] = useState(false);\n  const [isHovered, setIsHovered] = useState(false);\n\n  let btnClass = 'btn';\n  if (isPressed) btnClass += ' btn-pressed';\n  else if (isHovered) btnClass += ' btn-over';\n\n  return (\n    \u003cbutton\n      className={btnClass}\n      onMouseDown={() =\u003e setIsPressed(true)}\n      onMouseUp={() =\u003e setIsPressed(false)}\n      onMouseEnter={() =\u003e setIsHovered(true)}\n      onMouseLeave={() =\u003e setIsHovered(false)}\n    \u003e\n      {props.label}\n    \u003c/button\u003e\n  );\n}\n```\n\nYou can express the conditional classes more simply as an object:\n\n```js\nimport React, { useState } from 'react';\nimport classNames from 'classnames';\n\nexport default function Button (props) {\n  const [isPressed, setIsPressed] = useState(false);\n  const [isHovered, setIsHovered] = useState(false);\n\n  const btnClass = classNames({\n    btn: true,\n    'btn-pressed': isPressed,\n    'btn-over': !isPressed \u0026\u0026 isHovered,\n  });\n\n  return (\n    \u003cbutton\n      className={btnClass}\n      onMouseDown={() =\u003e setIsPressed(true)}\n      onMouseUp={() =\u003e setIsPressed(false)}\n      onMouseEnter={() =\u003e setIsHovered(true)}\n      onMouseLeave={() =\u003e setIsHovered(false)}\n    \u003e\n      {props.label}\n    \u003c/button\u003e\n  );\n}\n```\n\nBecause you can mix together object, array and string arguments, supporting optional `className` props is also simpler as only truthy arguments get included in the result:\n\n```js\nconst btnClass = classNames('btn', this.props.className, {\n  'btn-pressed': isPressed,\n  'btn-over': !isPressed \u0026\u0026 isHovered,\n});\n```\n\n### Alternate `dedupe` version\n\nThere is an alternate version of `classNames` available which correctly dedupes classes and ensures that falsy classes specified in later arguments are excluded from the result set.\n\nThis version is slower (about 5x) so it is offered as an opt-in.\n\nTo use the dedupe version with Node.js, Browserify, or webpack:\n\n```js\nconst classNames = require('classnames/dedupe');\n\nclassNames('foo', 'foo', 'bar'); // =\u003e 'foo bar'\nclassNames('foo', { foo: false, bar: true }); // =\u003e 'bar'\n```\n\nFor standalone (global / AMD) use, include `dedupe.js` in a `\u003cscript\u003e` tag on your page.\n\n### Alternate `bind` version (for [css-modules](https://github.com/css-modules/css-modules))\n\nIf you are using [css-modules](https://github.com/css-modules/css-modules), or a similar approach to abstract class 'names' and the real `className` values that are actually output to the DOM, you may want to use the `bind` variant.\n\n_Note that in ES2015 environments, it may be better to use the \"dynamic class names\" approach documented above._\n\n```js\nconst classNames = require('classnames/bind');\n\nconst styles = {\n  foo: 'abc',\n  bar: 'def',\n  baz: 'xyz',\n};\n\nconst cx = classNames.bind(styles);\n\nconst className = cx('foo', ['bar'], { baz: true }); // =\u003e 'abc def xyz'\n```\n\nReal-world example:\n\n```js\n/* components/submit-button.js */\nimport { useState } from 'react';\nimport classNames from 'classnames/bind';\nimport styles from './submit-button.css';\n\nconst cx = classNames.bind(styles);\n\nexport default function SubmitButton ({ store, form }) {\n  const [submissionInProgress, setSubmissionInProgress] = useState(store.submissionInProgress);\n  const [errorOccurred, setErrorOccurred] = useState(store.errorOccurred);\n  const [valid, setValid] = useState(form.valid);\n\n  const text = submissionInProgress ? 'Processing...' : 'Submit';\n  const className = cx({\n    base: true,\n    inProgress: submissionInProgress,\n    error: errorOccurred,\n    disabled: valid,\n  });\n\n  return \u003cbutton className={className}\u003e{text}\u003c/button\u003e;\n}\n```\n\n## Polyfills needed to support older browsers\n\n#### `classNames \u003e=2.0.0`\n\n`Array.isArray`: see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) for details about unsupported older browsers (e.g. \u003c= IE8) and a simple polyfill.\n\n## LICENSE [MIT](LICENSE)\n\nCopyright (c) 2018 Jed Watson.\nCopyright of the Typescript bindings are respective of each contributor listed in the definition file.\n","funding_links":[],"categories":["react","Uncategorized","JavaScript","Utilities","Code Design","Tools","React"],"sub_categories":["Uncategorized","style","CSS / Style","React Components","🎃ClassName"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJedWatson%2Fclassnames","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FJedWatson%2Fclassnames","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FJedWatson%2Fclassnames/lists"}