{"id":18441242,"url":"https://github.com/jamesknelson/react-cx","last_synced_at":"2025-04-07T22:32:12.819Z","repository":{"id":66191692,"uuid":"104425709","full_name":"jamesknelson/react-cx","owner":"jamesknelson","description":"Combine styles from CSS Modules with a `cx` prop.","archived":false,"fork":false,"pushed_at":"2017-12-27T09:32:57.000Z","size":36,"stargazers_count":23,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-23T01:35:48.614Z","etag":null,"topics":["css","react","style"],"latest_commit_sha":null,"homepage":"","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/jamesknelson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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,"publiccode":null,"codemeta":null}},"created_at":"2017-09-22T03:11:27.000Z","updated_at":"2023-08-23T11:26:11.000Z","dependencies_parsed_at":"2023-02-25T06:45:53.653Z","dependency_job_id":null,"html_url":"https://github.com/jamesknelson/react-cx","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Freact-cx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Freact-cx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Freact-cx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesknelson%2Freact-cx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesknelson","download_url":"https://codeload.github.com/jamesknelson/react-cx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247741312,"owners_count":20988371,"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":["css","react","style"],"created_at":"2024-11-06T06:36:00.612Z","updated_at":"2025-04-07T22:32:12.812Z","avatar_url":"https://github.com/jamesknelson.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"react-cx\n========\n\n[![Version](http://img.shields.io/npm/v/react-cx.svg)](https://www.npmjs.org/package/react-cx)\n\nAdd styles from CSS Modules with a `cx` prop:\n\n```jsx\n\u003cdiv\n  cx={['Arrow', { active }, color, 'length-'+length]}\n  className={className}\n /\u003e\n```\n\nInspired by [jareware/css-ns](https://github.com/jareware/css-ns). Uses [jedwatson/classnames](https://github.com/JedWatson/classnames) under the hood.\n\nInstall with npm:\n\n```sh\n# Adds react-cx to node_modules and package.json\nnpm install react-cx --save\n```\n\n\nWhy?\n----\n\nWhen styling components with [CSS modules](https://github.com/css-modules/css-modules), you'll often need join multiple class names together before passing them to the React `className` prop.\n\n```jsx\n// CSS Modules provide an object with your stylesheet's class names\nimport styles from './Theme.less'\n\nexport function({ active, className, color, length=1 }) {\n  const className = `\n    ${styles.Arrow}\n    ${active ? styles.active : ''}\n    ${styles[color] || ''}\n    ${styles['length-+'length] || ''}\n    ${className}\n  `\n  \u003cdiv className={className} /\u003e\n}\n```\n\nThe [classnames](https://github.com/JedWatson/classnames) package can help, but the resulting code still feels a little verbose after you've typed it for the 50th time.\n\n```jsx\nimport styles from './Theme.less'\n\n// classnames provides a helper to build `className` strings\nimport bindClassNames from 'classnames/bind'\nconst cx = bindClassNames(styles)\n\nexport function Arrow({ active, className='', color, length=1 }) {\n  return \u003cdiv className={cx('Arrow', { active }, color, 'length-'+length)+' '+className} /\u003e\n}\n```\n\nWith react-cx, you can add styles from your CSS modules directly to your elements by using the `cx` prop. It uses the same syntax as the classnames package, and still lets you append a raw `className` prop.\n\n```jsx\nimport styles from './Theme.less'\n\n// react-cx adds a `cx` prop to React by wrapping `React.createElement`\nimport getReactWithCX from './react-cx'\nconst React = getReactWithCX(styles)\n\nexport function Arrow({ active, className, color, length=1 }) {\n  return (\n    \u003cdiv\n      cx={['Arrow', { active }, color, 'length-'+length]}\n      className={className}\n     /\u003e\n  )\n}\n```\n\nOf course, the `cx` prop can also accept strings or plain objects:\n\n```jsx\nexport function Switch({ active, className, color='lifecycle', direction='down' }) {\n  return (\n    \u003cdiv cx={['Switch', { active }, color, direction]} className={className}\u003e\n      \u003cdiv cx=\"pivot\" /\u003e\n      \u003cArrow active={active} color={color} /\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n*These components are taken from my [React lifecycle simulators](https://reactarmory.com/guides/lifecycle-simulators).*\n\n\nHow does it work?\n-----------------\n\nIn React, JSX calls are translated to calls to `React.createElement()`. Thus, by wrapping `React.createElement()` with our own function, we can add support for new props without ever touching React's internals.\n\nIf you understand how `React.createElement()` works, the easiest way to grok this is to just view the source below. If you're not yet familiar with `React.createElement()`, head over to [React Armory](https://reactarmory.com/guides/learn-react-by-itself/react-basics) for a simple explanation with live examples and exercises.\n\n```js\nimport UnprefixedReact from 'react'\nimport classnames from 'classnames/bind'\n\nexport default function cx(styles, prop='cx') {\n  const bound = classnames.bind(styles)\n\n  function getProps(props) {\n    if (!props) return props\n\n    if (props.cx) {\n      const result = Object.assign({}, props)\n      delete result.cx\n      const args = Array.isArray(props.cx) ? props.cx : [props.cx]\n      result.className = bound(...args)\n      if (props.className) result.className += ' '+props.className\n      return result\n    }\n    return props\n  }\n  function createElement(type, props, ...children) {\n    return UnprefixedReact.createElement(type, getProps(props), ...children)\n  }\n  function cloneElement(element, props, ...children) {\n    return UnprefixedReact.cloneElement(element, getProps(props), ...children)\n  }\n  return Object.assign({}, UnprefixedReact, {\n    createElement,\n    cloneElement\n  })\n}\n```\n\n\nMore examples\n-------------\n\nThese components are all taken from my [React lifecycle simulators](https://reactarmory.com/guides/lifecycle-simulators).\n\n```jsx\nexport function Indicator({ active, className, color, icon, label, noMobile, scheduled, style }) {\n  return (\n    \u003cdiv cx={['Indicator', (scheduled || active) \u0026\u0026 color, { active, 'no-mobile': noMobile }]} className={className} style={style}\u003e\n      { icon \u0026\u0026\n        \u003cdiv cx=\"icon\"\u003e{icon}\u003c/div\u003e\n      }\n      \u003cdiv cx=\"label\"\u003e{label}\u003c/div\u003e\n    \u003c/div\u003e\n  )\n}\n\nexport function Switch({ active, className, color='lifecycle', direction='down', style }) {\n  return (\n    \u003cdiv cx={['Switch', { active }, color, direction]} className={className} style={style}\u003e\n      \u003cdiv cx=\"pivot\" /\u003e\n      \u003cArrow active={active} color={color} headless={direction === 'down'} /\u003e\n    \u003c/div\u003e\n  )\n}\n\nfunction SwitchedSetter({ className, color, icon, label, noMobile, setActive, style, switchActive, willSet }) {\n  return (\n    \u003cdiv cx={['SwitchedSetter', { 'no-mobile': noMobile }]} className={className} style={style}\u003e\n      \u003cSwitch active={switchActive} direction={willSet ? 'right' : 'down' } /\u003e\n      \u003cIndicator active={setActive} color={color} icon={icon} label={label} scheduled={willSet} /\u003e\n      \u003cArrow cx='horizontal-wire' active={setActive} color={color} headless length={4} /\u003e\n      \u003cArrow cx='vertical-wire' active={setActive} color={color} headless /\u003e\n      \u003cArrow cx='output' active={setActive || (switchActive \u0026\u0026 !willSet)} color={switchActive ? 'lifecycle' : color} /\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n\nLicense\n-------\n\n[MIT](/LICENSE) Copyright \u0026copy; 2017 James K Nelson","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesknelson%2Freact-cx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesknelson%2Freact-cx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesknelson%2Freact-cx/lists"}