{"id":17816561,"url":"https://github.com/hswolff/create-class-names","last_synced_at":"2025-09-24T11:31:23.115Z","repository":{"id":139815356,"uuid":"124703665","full_name":"hswolff/create-class-names","owner":"hswolff","description":"A utility to extend the values of a classNames object.","archived":false,"fork":false,"pushed_at":"2018-06-20T20:08:18.000Z","size":73,"stargazers_count":16,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-12T04:12:24.740Z","etag":null,"topics":["classnames","css-modules","react","styles"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hswolff.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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,"publiccode":null,"codemeta":null}},"created_at":"2018-03-10T22:26:58.000Z","updated_at":"2023-06-08T11:19:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"0e21d49b-7e04-4ed9-bc7b-e0edc1f5405e","html_url":"https://github.com/hswolff/create-class-names","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hswolff%2Fcreate-class-names","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hswolff%2Fcreate-class-names/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hswolff%2Fcreate-class-names/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hswolff%2Fcreate-class-names/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hswolff","download_url":"https://codeload.github.com/hswolff/create-class-names/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234077616,"owners_count":18775937,"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":["classnames","css-modules","react","styles"],"created_at":"2024-10-27T16:38:29.484Z","updated_at":"2025-09-24T11:31:17.821Z","avatar_url":"https://github.com/hswolff.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# create-class-names\n\n[![build status](https://img.shields.io/travis/hswolff/create-class-names/master.svg?style=flat-square)](https://travis-ci.org/hswolff/create-class-names)\n[![npm version](https://img.shields.io/npm/v/create-class-names.svg?style=flat-square)](https://www.npmjs.com/package/create-class-names)\n[![npm downloads](https://img.shields.io/npm/dm/create-class-names.svg?style=flat-square)](https://www.npmjs.com/package/create-class-names)\n\nA utility to define an API for assigning custom classNames to nested elements in a React Component.\n\nUseful for global styles, css-modules, and css-in-js.\n\nNote: This is not a replacement for the very awesome [classnames](https://github.com/JedWatson/classnames) library. This is meant to be used in conjunction with classnames. Think of this library as a way to combine usages of classnames.\n\n## What is this?\n\nCommonly React developers will manually expose a `className` prop to their React Component to allow users of that component to customize the style. Also it's very common to use [classnames](https://github.com/JedWatson/classnames) to concatenate those classNames.\n\n```js\nfunction Banner(props) {\n  const { children, className } = props;\n  return (\n    \u003cdiv className={classNames('container', className)}\u003e\n      \u003cspan className=\"alert\"\u003e\u0026#x26a0;\u003c/span\u003e\n      \u003cdiv className=\"text\"\u003e{children}\u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nHowever if you want to expose the ability to customize the className for a child component, there's no clear way to do that. A common method is to expose another `prop`, such as `textClassName`.\n\n```js\nfunction Banner(props) {\n  const { children, textClassName } = props;\n  return (\n    \u003cdiv className={classNames('container', className)}\u003e\n      \u003cspan className=\"alert\"\u003e\u0026#x26a0;\u003c/span\u003e\n      \u003cdiv className={classNames('text', textClassName)}\u003e{children}\u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\nHowever this approach doesn't scale well.\n\n## Use a theme object\n\nA more structured way to solve this is to use a theme object.\n\n```js\nfunction Banner(props) {\n  const { children, theme } = props;\n  return (\n    \u003cdiv className={theme.container}\u003e\n      \u003cspan className={theme.alert}\u003e\u0026#x26a0;\u003c/span\u003e\n      \u003cdiv className={theme.text}\u003e\n        \u003cspan className={theme.innerText}\u003e{children}\u003c/span\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\nBanner.defaultProps = {\n  theme: {\n    container: 'globalContainerClassName',\n  },\n};\n```\n\nThis allows parent componets to customize what classNames are given however it then becomes difficult to keep the default classNames.\n\n```js\nconst Page = () =\u003e (\n  \u003cBanner\n    theme={{\n      container: 'customContainerClass',\n    }}\n    {/* This removes the default className */}\n  /\u003e\n);\n```\n\nHowever keeping the default value is very cumbersome.\n\n```js\nconst Page = () =\u003e (\n  \u003cBanner\n    theme={{\n      container: `${Banner.defaultProps.theme.container} customContainerClass`,\n    }}\n  /\u003e\n);\n```\n\nThat's where `createClassNames` comes to the rescue!\n\n## Usage\n\n```js\nconst base = {\n  container: 'container',\n};\n\n// 1. This is essentially a shallow clone of base.\nconst result = createClassNames(base);\n\nassert.deepEquals(result, {\n  container: 'container',\n});\n\n// 2. Extend the base classNames.\n// If the extended values are not strings then they are ignored.\nconst result = createClassNames(base, {\n  container: 'pageContainer',\n});\n\nassert.deepEquals(result, {\n  container: 'container pageContainer',\n});\n\n// 3. Provide a default custom merge function.\nconst result = createClassNames(\n  base,\n  {\n    container: 'pageContainer',\n  },\n  (val, baseVal, key, result) =\u003e {\n    return val;\n  }\n);\n\nassert.deepEquals(result, {\n  container: 'pageContainer',\n});\n\n// 4. Provide a custom merge behavior per property.\nconst result = createClassNames(base, {\n  container: (baseVal, key, result) =\u003e {\n    return `${baseVal} ${baseVal}`;\n  },\n});\n\nassert.deepEquals(result, {\n  container: 'container container',\n});\n```\n\n## Example\n\nLive demo on Codesandbox.\n\n[![Edit createClassNames Demo](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/13zn2oj594)\n\nA more in depth example with React.\n\n```js\n// With css-modules\nimport styles from './Banner.css';\nconst baseStyles = styles;\n\n// With global styles\nconst baseStyles = {\n  container: 'container',\n  alert: 'alert',\n  text: 'text',\n  // Empty string here because there is no base styles but you want\n  // to allow parent components the ability to customize that element.\n  innerText: '',\n};\n\nfunction Banner(props) {\n  const { children, theme } = props;\n\n  // Merges base and theme className values onto the same property.\n  const theme = createClassNames(baseStyles, theme);\n\n  return (\n    \u003cdiv className={theme.container}\u003e\n      \u003cspan className={theme.alert}\u003e\u0026#x26a0;\u003c/span\u003e\n      \u003cdiv className={theme.text}\u003e\n        \u003cspan className={theme.innerText}\u003e{children}\u003c/span\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  );\n}\n\nconst Page = () =\u003e (\n    {/* Just uses default styles */}\n    \u003cBanner\u003eDefault Styles\u003c/Banner\u003e\n\n    {/* Customizing classNames */}\n    \u003cBanner\n      theme={{\n        container: 'secondBanner',\n        alert: 'secondBannerAlert',\n        innerText: 'secondBannerInnerText'\n      }}\n    \u003e\n      Custom Styles\n    \u003c/Banner\u003e\n\n    {/*\n        If you pass a function as a value for a property then you can customize\n        what resulting className is given.\n    */}\n    \u003cBanner\n      theme={{\n        container: (baseStyleValue, key, result) =\u003e {\n            // baseStyleValue === 'container'\n            // key === 'container'\n            // result === the resulting theme object\n            return 'secondBanner';\n        }\n      }}\n    \u003e\n      Over-riding container style\n    \u003c/Banner\u003e\n)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhswolff%2Fcreate-class-names","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhswolff%2Fcreate-class-names","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhswolff%2Fcreate-class-names/lists"}