{"id":13618027,"url":"https://github.com/reacttips-dev/stylex","last_synced_at":"2025-04-09T13:07:36.031Z","repository":{"id":45565716,"uuid":"330083538","full_name":"reacttips-dev/stylex","owner":"reacttips-dev","description":"Write CSS-in-JS with atomic support. Like Facebook's Stylex!","archived":false,"fork":false,"pushed_at":"2021-10-21T14:10:53.000Z","size":2810,"stargazers_count":287,"open_issues_count":6,"forks_count":19,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-02T11:07:15.763Z","etag":null,"topics":["css","css-in-js"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/reacttips-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-01-16T04:27:06.000Z","updated_at":"2025-01-04T02:37:35.000Z","dependencies_parsed_at":"2022-08-28T05:51:04.376Z","dependency_job_id":null,"html_url":"https://github.com/reacttips-dev/stylex","commit_stats":null,"previous_names":["ladifire-opensource/stylex"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reacttips-dev%2Fstylex","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reacttips-dev%2Fstylex/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reacttips-dev%2Fstylex/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/reacttips-dev%2Fstylex/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/reacttips-dev","download_url":"https://codeload.github.com/reacttips-dev/stylex/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248045231,"owners_count":21038553,"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","css-in-js"],"created_at":"2024-08-01T20:01:52.912Z","updated_at":"2025-04-09T13:07:36.006Z","avatar_url":"https://github.com/reacttips-dev.png","language":"TypeScript","readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"https://stylex.vercel.app/logo-black.png\" height=\"96\" /\u003e\n  \u003cbr /\u003e\n  \u003csmall\u003eWrite CSS in JS with Atomic first, like Facebook do!\u003c/small\u003e\n\u003c/h1\u003e\n\n## [About Stylex](#about-stylex)\n\n**NOTE: The idea of stylex originated from Facebook.**\n\nThe underlying idea was to not discard idiomatic CSS but to make it\neasier to maintain and keep the good parts of CSS that developers are\nused to enjoying. The number one priority was readability and\nmaintainability, which are issues compounded at scale.\n\nSee Facebook React conf video for more about Stylex: [Click here](https://youtu.be/9JZHodNR184?t=229)\n\n## [Installation](#installation)\n\nYarn users:\n\n```bash\nyarn add @ladifire-opensource/stylex\n```\n\nNpm users:\n\n```bash\nnpm install @ladifire-opensource/stylex\n```\n\nThe second step is depending on what bundler you use, for webpack you\nneed to install a webpack plugin\n\n```bash\nyarn add @ladifire-opensource/stylex-webpack-plugin\n```\n\nIf you're using `Nextjs`:\n\n```bash\nyarn add @ladifire-opensource/stylex-nextjs-plugin\n```\n\n### [Setup with Webpack](#setup-with-webpack)\n\nFirst, we need import `stylex-webpack-plugin`:\n\n```js\nconst StylexPlugin = require(\"@ladifire-opensource/stylex-webpack-plugin\");\n```\n\nThen, in `plugins` section, add this:\n\n```js\n plugins: [\n    //...other plugins\n\n    new StylexPlugin(),\n```\n\nLast thing, add this in `rules` section:\n\n```js\nrules: [\n      {\n        test: /\\.(ts|tsx)$/,\n        use: [\n          // ...keeps your other loaders here\n\n          // and stylex-loader goes here\n          {\n            loader: StylexPlugin.loader,\n            options: {\n              inject: false,\n            },\n          },\n        ],\n      },\n```\n\n### [Setup with Babel](#setup-with-babel)\n\nThis is example of Babel config with stylex:\n\n```js\n/**\n * Copyright (c) Ladifire, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n/*eslint-env node*/\nmodule.exports = {\n  presets: [\"@babel/react\", \"@babel/env\", \"@babel/preset-typescript\"],\n  plugins: [\n    \"@babel/plugin-syntax-dynamic-import\",\n    \"@babel/plugin-proposal-object-rest-spread\",\n    \"@babel/plugin-transform-runtime\",\n    [\"@babel/plugin-transform-modules-commonjs\"],\n    [\n      \"@babel/plugin-transform-spread\",\n      {\n        loose: true,\n      },\n    ],\n    [\"@babel/plugin-proposal-decorators\", { legacy: true }],\n    [\"@babel/plugin-proposal-class-properties\", { loose: true }],\n    [\n      \"@ladifire-opensource/babel-plugin-transform-stylex\",\n      {\n        inject: true, // will inject compiled css to stylesheet in head\n      },\n    ],\n  ],\n};\n```\n\n### [Setup with Nextjs](#setup-with-nextjs)\n\nFirst thing, you need add `next-transpile-modules` to your project.\n\nJust run:\n\n```bash\nyarn add -D next-transpile-modules\n```\n\nThen in `next.config.js`, add these lines:\n\n```js\nconst withTM = require(\"next-transpile-modules\")(\n  [\"@ladifire-opensource/stylex\"],\n  { unstable_webpack5: true }\n);\nconst withStylex = require(\"@ladifire-opensource/stylex-nextjs-plugin\");\n\nmodule.exports = withStylex({\n  inject: true, // for nextjs, we must inject style to head\n})(withTM());\n```\n\n### [Setup with Vue](#setup-with-vue)\n\nAdd these lines in `vue.config.js`:\n\n```js\nconst StylexPlugin = require(\"@ladifire-opensource/stylex-webpack-plugin\");\n\nmodule.exports = {\n  configureWebpack: {\n    module: {\n      rules: [\n        {\n          test: /\\.(tsx|ts|js|mjs|jsx)$/,\n          use: StylexPlugin.loader,\n        },\n      ],\n    },\n    plugins: [new StylexPlugin()],\n  },\n};\n```\n\nThen you can write like this in your `.vue`:\n\n```js\n\u003cscript\u003e\n\nimport stylex from '@ladifire-opensource/stylex'\n\nconst styles = stylex.create({\n    button: {\n        borderRadius: 8,\n        padding: 16,\n        backgroundColor: \"#1DA1F2\",\n        color: \"#fff\"\n    },\n});\n\nexport default {\n  name: 'HelloWorld',\n  props: {\n    msg: String\n  },\n  computed: {\n    buttonClasses() {\n      return stylex(styles.button);\n    }\n  }\n}\n\u003c/script\u003e\n```\n\n### [Setup with Create React App](#setup-with-create-react-app)\n\nFollow `craco.js` installation [guide]('https://github.com/gsoft-inc/craco/blob/master/packages/craco/README.md#installation').\n\nFinally in `craco.config.js` add:\n\n```js\nmodule.exports = {\n  // ...\n  babel: {\n    /// ...\n    plugins: [\n      /// ...\n      [\n        \"@ladifire-opensource/babel-plugin-transform-stylex\",\n        {\n          inject: true,\n        },\n      ],\n    ],\n  },\n};\n```\n\n### [Setup with Angular](#setup-with-angular)\n\n_Under construction!!!_\n\n## [Examples](#examples)\n\n- React minimal example: [View code](https://github.com/ladifire-opensource/react-stylex-minimal)\n- Nextjs examples: [View code](https://github.com/ladifire-opensource/stylex.vercel.app), [other nextjs example](https://github.com/ladifire-opensource/stylex/tree/main/packages/stylex-vuejs-examples)\n- Vue example: [View code](https://github.com/ladifire-opensource/stylex/tree/main/packages/stylex-vuejs-examples)\n\n## [How to use stylex?](#how-to-use-stylex)\n\nThere're some methods you can you with stylex:\n\n### Create new stylex object `(stylex.create)`\n\nThis method will create a new stylex object:\n\n```js\nimport stylex from \"@ladifire-opensource/stylex\";\n\nconst styles = stylex.create({\n  root: {\n    fontWeight: 700,\n    color: \"blue\",\n  },\n  button: {\n    borderRadius: 8,\n  },\n});\n```\n\nThen we can use as:\n\n```js\n\u003cdiv className={stylex(styles.root)}\u003eComponent\u003c/div\u003e\n```\n\nThe arguments of `stylex(...args)` can be separated by comma:\n\n```js\n\u003cdiv className={stylex(styles.root, styles.button)}\u003eComponent\u003c/div\u003e\n```\n\nor as an array:\n\n```js\n\u003cdiv className={stylex([styles.root, styles.button])}\u003eComponent\u003c/div\u003e\n```\n\n### Dedupe stylex objects `(stylex.dedupe)`\n\nThis method will dedupe (override) duplicate style properties:\n\n```js\n\u003cdiv\n  className={stylex.dedupe(\n    {\n      color: \"var(--primary-text)\",\n    },\n    isError\n      ? {\n          color: \"var(--negative)\",\n        }\n      : null\n  )}\n\u003e\n  Dedupe\n\u003c/div\u003e\n```\n\n### Create a keyframes animation name `(stylex.keyframes)`\n\n```js\nlet j = stylex.create({\n  dark: {\n    backgroundColor: \"var(--placeholder-icon)\",\n  },\n  paused: {\n    animationPlayState: \"paused\",\n  },\n  root: {\n    animationDirection: \"alternate\",\n    animationDuration: \"1s\",\n    animationIterationCount: \"infinite\",\n    animationName: stylex.keyframes({\n      \"0%\": {\n        opacity: 0.25,\n      },\n      \"100%\": {\n        opacity: 1,\n      },\n    }),\n    animationTimingFunction: \"steps(10,end)\",\n    backgroundColor: \"var(--wash)\",\n    opacity: 0.25,\n  },\n});\n```\n\n### Compose (merge) stylex objects `(stylex.compose)`\n\n```js\nconst s = stylex.compose(\n  {\n    color: \"red\",\n    backgroundColor: \"blue\",\n  },\n  {\n    backgroundColor: \"white\",\n  }\n);\n```\n\nThe above code will transformed to:\n\n```js\nconst s = {\n  color: \"a512sdfe5\", // red\n  backgroundColor: \"wer115asse\", // white\n};\n```\n\n#### Quick uses\n\n_Describe some common static methods for quick uses, eg: stylex.absolute, ..._\n\n### [Plugin options](#plugin-options)\n\n#### Inject css to compiled js\n\nBy default, stylex will inject css to stylesheet object in `\u003chead\u003e` of html document.\n\nThere is no extra reference links of stylesheets to inject.\n\nThe webpack setup should be:\n\n```js\n...\nrules: [\n      {\n        test: /\\.(ts|tsx)$/,\n        exclude: STANDARD_EXCLUDE,\n        use: [\n          babelLoaderConfig,\n          {\n            loader: StylexPlugin.loader,\n            options: {\n              inject: true,\n            },\n          },\n        ],\n      },\n\n...\n```\n\nIn the compiled js, there're something like this will be injected:\n\n```js\ninject('.avcdd15645{color: \"red\"}');\n```\n\nThen the stylex runtime code will excute the `inject` function and add `'.avcdd15645{color: \"red\"}'`\nto the stylesheet in the `\u003chead\u003e` section.\n\n#### Separate css into .css files\n\nIn case you want to use stylex with `mini-css-extract-plugin` to seprate css\ninto reference links, you can setup in your webpack config as bellow:\n\n```js\n...\nconst ExtractTextPlugin = require('mini-css-extract-plugin');\nconst StylexPlugin = require(\"@ladifire-opensource/stylex-webpack-plugin\");\n\n...\nrules: [\n      {\n        test: /\\.(ts|tsx)$/,\n        exclude: STANDARD_EXCLUDE,\n        use: [\n          babelLoaderConfig,\n          {\n            loader: StylexPlugin.loader,\n            options: {\n              inject: false, // set false to ignore inject css to js\n            },\n          },\n        ],\n      },\n\n...\n\nplugins: [\n   new StylexPlugin(),\n   new ExtractTextPlugin({\n      filename: '[name].[contentHash:11].css',\n      chunkFilename: '[name].[contentHash:11].css',\n    }),\n\n...\n```\n\n### Babel\n\nThis is example of stylex's babel config:\n\n```js\nmodule.exports = {\n  presets: [\"@babel/react\", \"@babel/env\", \"@babel/preset-typescript\"],\n  plugins: [\n    \"@babel/plugin-syntax-dynamic-import\",\n    \"@babel/plugin-proposal-object-rest-spread\",\n    \"@babel/plugin-transform-runtime\",\n    [\"@babel/plugin-transform-modules-commonjs\"],\n    [\n      \"@babel/plugin-transform-spread\",\n      {\n        loose: true,\n      },\n    ],\n    [\"@babel/plugin-proposal-decorators\", { legacy: true }],\n    [\"@babel/plugin-proposal-class-properties\", { loose: true }],\n    [\n      \"@ladifire-opensource/babel-plugin-transform-stylex\",\n      {\n        inject: true, // will inject compiled css to stylesheet in head\n      },\n    ],\n  ],\n};\n```\n\n### SSR support\n\nSee `stylex-nextjs-examples` for setup stylex with nextjs.\n\n### Others\n\n#### Pass stylex through props (Reactjs)\n\nIf you using Reactjs, consider to use **xstyle** props to pass some stylex class from\nparent to child. Let's see bellow example:\n\n```js\nimport * as React from \"react\";\nimport stylex from \"@ladifire-opensource/stylex\";\nimport ChildComponent from \"./path/to/child\";\n\ntype Style = \"root\";\n\nconst styles = stylex.create({\n  root: {\n    color: \"red\",\n  },\n});\n\nconst Parent = () =\u003e {\n  return (\n    \u003cChildComponent\n      xstyle={styles.root}\n      //...otherProps\n    /\u003e\n  );\n};\n```\n\nThe `xstyle` prop is a good method because it helps to combine style props under one namespace\nand doesn't populate the global orios environment and it looks similar to the goal of\nsx prop.\n\nThen in your child component you can use `xstyle` props as:\n\n```js\nimport * as React from \"react\";\n\nimport stylex from \"@ladifire-opensource/stylex\";\n\nconst styles = stylex.create({\n  root: {\n    backgroundColor: \"red\",\n  },\n});\n\nconst ChildComponent = (props) =\u003e {\n  const { xstyle } = props;\n\n  return \u003cdiv className={stylex(styles.root, xstyle)}\u003eChild\u003c/div\u003e;\n};\n```\n\n#### Theming with stylex\n\nStylex support multiple theming. A \"theme\" is declared by given it an object of\nvariables, like this:\n\n```js\nconst defaultThemeVariables = {\n  \"primary-icon\": \"rgb(15, 20, 25)\",\n  \"primary-text\": \"rgb(15, 20, 25)\",\n  \"primary-text-on-media\": \"#FFFFFF\",\n};\n```\n\nThere're two theme objects in stylex: **rootTheme** and **customTheme**.\nTo set **rootTheme**:\n\n```js\nimport CometStyleXSheet from \"@ladifire-opensource/stylex-theme\";\n\n...\n\nCometStyleXSheet.rootStyleSheet.setRootTheme(defaultThemeVariables);\n```\n\nand **customTheme**:\n\n```js\nCometStyleXSheet.rootStyleSheet.setCustomTheme(customThemeVariables);\n```\n\nTo change theme:\n\n```js\nCometStyleXSheet.rootStyleSheet.toggleCustomTheme(!isCustomThemeActive);\n```\n\nThis is example for React users:\n\n```js\nimport CometStyleXSheet from \"@ladifire-opensource/stylex-theme\";\n\nimport { themeDataBase } from \"./themeDataBase\";\nimport { themeDataCustom } from \"./themeDataCustom\";\n\nexport const ThemingExamples = () =\u003e {\n  React.useEffect(() =\u003e {\n    CometStyleXSheet.rootStyleSheet.setRootTheme(themeDataBase);\n    CometStyleXSheet.rootStyleSheet.setCustomTheme(themeDataCustom);\n  }, []);\n\n  const [isDark, setIsDark] = React.useState \u003c boolean \u003e (() =\u003e false);\n  const toggleIsDark = React.useCallback(\n    (event: React.ChangeEvent\u003cHTMLInputElement\u003e) =\u003e {\n      const target = event.target;\n      setIsDark(target.checked);\n      CometStyleXSheet.rootStyleSheet.toggleCustomTheme(!isDark);\n    },\n    [isDark, setIsDark]\n  );\n\n  // ...\n};\n```\n\n## Thanks to\n\n- We'd like to send a big thanks to: johanholmerin for style9 (an other stylex cover)\n- We'd like to thanks Facebook very much (most of javascript code in stylex is re-write from built code of Facebook)\n\n## Contributing\n\nContributions are always welcome, no matter how large or small!\n\n#### Setup\n\nFork the `stylex` repository to your GitHub Account.\n\nThen, run: `yarn install`\n\nTo see reactjs demo, cd to `stylex-reactjs-examples` and following steps in\nREADME.md to run Reactjs demo\n\n## Join Stylex Community (Facebook group)\n\nVisit [this link](https://www.facebook.com/groups/713597106002279) to join Stylex community.\n\n### License\n\nStylex is [MIT licensed](./LICENSE).\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freacttips-dev%2Fstylex","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Freacttips-dev%2Fstylex","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Freacttips-dev%2Fstylex/lists"}