{"id":13394189,"url":"https://github.com/giuseppeg/style-sheet","last_synced_at":"2025-03-13T20:31:19.912Z","repository":{"id":55857205,"uuid":"150797261","full_name":"giuseppeg/style-sheet","owner":"giuseppeg","description":"⚡️💨 Fast styles in JavaScript with support for static CSS extraction.","archived":true,"fork":false,"pushed_at":"2020-12-11T03:39:19.000Z","size":764,"stargazers_count":225,"open_issues_count":5,"forks_count":9,"subscribers_count":10,"default_branch":"master","last_synced_at":"2024-07-31T17:21:26.241Z","etag":null,"topics":["css","css-in-js","react","reactnative"],"latest_commit_sha":null,"homepage":"https://giuseppegurgone.com/style-sheet","language":"JavaScript","has_issues":false,"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/giuseppeg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"giuseppeg"}},"created_at":"2018-09-28T21:40:57.000Z","updated_at":"2023-11-04T09:39:52.000Z","dependencies_parsed_at":"2022-08-15T07:51:20.468Z","dependency_job_id":null,"html_url":"https://github.com/giuseppeg/style-sheet","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giuseppeg%2Fstyle-sheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giuseppeg%2Fstyle-sheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giuseppeg%2Fstyle-sheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giuseppeg%2Fstyle-sheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/giuseppeg","download_url":"https://codeload.github.com/giuseppeg/style-sheet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243478048,"owners_count":20297183,"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","react","reactnative"],"created_at":"2024-07-30T17:01:11.916Z","updated_at":"2025-03-13T20:31:19.597Z","avatar_url":"https://github.com/giuseppeg.png","language":"JavaScript","funding_links":["https://github.com/sponsors/giuseppeg"],"categories":["JavaScript"],"sub_categories":[],"readme":"# StyleSheet ⚡️💨\n\n\u003ca href=\"https://travis-ci.org/giuseppeg/style-sheet\"\u003e\u003cimg alt=\"Build Status\" src=\"https://travis-ci.org/giuseppeg/style-sheet.svg?branch=master\"\u003e\u003c/a\u003e \u003ca href=\"https://github.com/giuseppeg/style-sheet\"\u003e\u003cimg width=\"18px\" height=\"18px\" alt=\"source code\" src=\"https://github.com/fluidicon.png\"\u003e\u003c/a\u003e\n\nStyleSheet is a library to author styles in JavaScript.\n\nIt is **fast** and generates optimized, tiny bundles by compiling rules to **atomic CSS** that can then be **extracted to .css file** with a Babel plugin.\n\n[Play with StyleSheet on **CodeSandbox**](https://codesandbox.io/s/crazy-dubinsky-nrs7n?fontsize=14)!\n\n```js\nimport { StyleSheet, StyleResolver } from 'style-sheet'\n\nconst styles = StyleSheet.create({\n  one: {\n    color: 'red',\n  },\n  another: {\n    color: 'green'\n  }\n})\n\nconst className = StyleResolver.resolve([styles.one, styles.another])\n```\n\nInstead of making use of the Cascade, StyleSheet resolves styles deterministically based on their application order.\n\n```js\nStyleResolver.resolve([styles.one, styles.another])\n// color is green\n\nStyleResolver.resolve([styles.another, styles.one])\n// color is red\n```\n\n`StyleResolver.resolve` works like `Object.assign` and merges rules right to left.\n\nStyleSheet comes with built-in support for pseudo classes and media queries, i18n, React and customizable `css` prop.\n\nThe StyleSheet library API is highly inspired to React Native and React Native for Web's and implements a styling solution that is similar to the one used in the new facebook.com website:\n\n\u003e This sounds very similar to what we use internally at Facebook for the new version of the site :) \u0026quot;Atomic\u0026quot; CSS via a CSS-in-JS library, that\u0026#39;s extracted to static CSS files.\n[Building the New facebook.com](https://developers.facebook.com/videos/2019/building-the-new-facebookcom-with-react-graphql-and-relay/) touches on it (around 28:40 in the video).\u003c/p\u003e\u0026mdash; Daniel Lo Nigro (@Daniel15) Software Engineer at Facebook\n\u003e [August 12, 2019](https://twitter.com/Daniel15/status/1160980442041896961)\n\n\u003cimg width=\"500\" alt=\"\" role=\"presentation\" src=\"https://user-images.githubusercontent.com/711311/65828122-b704e080-e297-11e9-9659-4c177b60b42e.png\"\u003e\n\n## Getting started\n\nFirstly, install the package:\n\n```\nnpm i --save style-sheet\n```\n\nThe package exposes a `StyleSheet` and `StyleResolver` instances that are used to respectively create rulesets and resolve (apply) them to class names.\n\n```js\nimport { StyleSheet, StyleResolver } from 'style-sheet'\n```\n\nUse `StyleSheet.create` to create a style object of rules.\n\n```js\nconst styles = StyleSheet.create({\n  one: {\n    color: 'red',\n  },\n  another: {\n    color: 'green'\n  }\n})\n```\n\nAnd `StyleResolver.resolve` to consume the `styles`:\n\n```js\nStyleResolver.resolve([styles.one, styles.another])\n```\n\nRemember the order in which you pass rules to `StyleResolver.resolve` matters!\n\n### Pseudo classes, media queries and other *selectors*\n\nStyleSheet supports simple state selectors, media queries and shallow combinator selectors like:\n\n```js\nconst styles = StyleSheet.create({\n  root: {\n    color: 'red',\n    '\u0026:hover' { // state selector\n      color: 'green'\n    },\n    ':focus \u003e \u0026': { // shallow combinator selector\n      color: 'green'\n    },\n    ':focus + \u0026': { // shallow combinator selector\n      color: 'blue'\n    },\n    '@media (min-width: 678px)': { // media query\n      color: 'yellow'\n    }\n  },\n})\n```\n\n## Styles resolution\n\n`StyleSheet.create` converts rules to arrays of atomic CSS classes. Every atomic CSS class corresponds to a declaration inside of the rule:\n\n```js\nconst rules = StyleSheet.create({\n  rule: {\n    display: 'block', // declaration\n    color: 'green'    // declaration\n  }\n})\n```\n\n`StyleResolver.resolve` then, accepts a single rule or an array of rules and it will merge them deterministically in application order (left to right). Finally it inserts the computed styles into the page.\n\nTo make sure that styles are resolved deterministically some rules apply:\n\n1. Shorthand properties are inserted first.\n2. Longhand properties override shorthands, always!\n3. States are sorted as follow: `link`, `visited`, `hover`, `focus-within`, `focus-visible`, `focus`, `active` meaning that `active` overrides `focus` and `hover` for example.\n4. Shorthand and longhand properties used inside of combinator selectors are inserted after their corrispective regular groups.\n5. Media queries are sorted in a mobile first manner.\n\nFor simplicity sake, generally we encourage not use these advanced selectors and simply resolve rules conditionally at runtime based on application state. Note that this won't stop you from extracting styles to .css file!\n\n\n## Server side rendering\n\nTo render on the server, you can access the underlying style sheet that the library is using at any time with `StyleResolver.getStyleSheet()`.\n\nThis method returns an ordered StyleSheet that exploses two methods:\n\n* `getTextContent` to get the atomic CSS for the rules that have been resolved.\n* `flush` to `getTextContent` and clear the stylesheet - useful when a server deamon is rendering multiple pages.\n\n```js\nimport { StyleResolver } from 'style-sheet'\n\nconst html = `\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta charset=utf-8\u003e\n    \u003ctitle\u003emy app\u003c/title\u003e\n    \u003cstyle id=\"__style_sheet__\"\u003e${StyleResolver.getStyleSheet().flush()}\u003c/style\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cmain\u003e${renderedHTML}\u003c/main\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n`\n```\n\nBy setting the `id` attribute to `__style_sheet__` StyleSheet can hydrate styles automatically on the client.\n\n## Extracting to static .css file\n\nStyleSheet comes with a Babel plugin that can extract static rules. This means that your styles are not computed at runtime or in JavaScript and can be served via `link` tag.\n\nJust add `style-sheet/babel` to `plugins` in your babel configuration:\n\n```json\n{\n  \"plugins\": [\n    \"style-sheet/babel\"\n  ]\n}\n```\n\nand compile your JavaScript files with Babel.\n\nOnce Babel is done compiling you can import the `getCss` function from `style-sheet/babel` to get the extracted CSS:\n\n```js\nimport { writeFileSync } from 'fs'\nimport { getCss } from 'style-sheet/babel'\n\nconst bundleFilePath = './build/bundle.css'\nwriteFileSync(bundleFilePath, getCss())\n```\n\nIn your page then you can reference the `bundleFilePath`:\n\n```diff\nconst html = `\n\u003c!doctype html\u003e\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003cmeta charset=utf-8\u003e\n    \u003ctitle\u003emy app\u003c/title\u003e\n+    \u003clink id=\"__style_sheet__\" rel=\"stylesheet\" href=\"./build/bundle.css\"\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003cmain\u003e${renderedHTML}\u003c/main\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n`\n```\n\nNote that StyleSheet **can also reconcile extracted styles!!!** You just need to make sure that the `link` tag has the `__style_sheet__` set, and keep in mind that CORS apply.\n\nWhen the Babel plugin can't resolve styles to static, it flags them as dynamic and it leaves them in JavaScript. For this reason it is always a good idea to define dynamic styles in separate rules.\n\n### Configuration\n\nBy default the plugin looks for references to `StyleSheet` when they are imported from `style-sheet`. However both can be configured, via plugin options:\n\n* `importName` - default is `StyleSheet` and the plugin looks for `StyleSheet.create`.\n* `packageName` - default is `style-sheet` but when using advanced features (see below) you can point to your custom setup.\n* `stylePropName` - default is `css`. In React the plugin looks for inline styles defined via this prop and extracts them.\n* `stylePropPackageName` - mandatory. When using the style prop you need to set this path to point to where you setup your custom `createElement` (see below).\n* `rtl` - boolean. When set generates I18n styles and extracts them too.\n\n```json\n{\n  \"plugins\": [\n    [\n      \"style-sheet/babel\",\n      {\n        \"importName\": \"StyleSheet\",\n        \"packageName\": \"./path/to/customInstance\",\n        \"stylePropName\": \"css\",\n        \"stylePropPackageName\": \"./path/to/createElement.js\",\n        \"rtl\": true\n      }\n    ]\n  ]\n}\n```\n\nThis is useful when StyleSheet is useds in custom ways like described in the advanced usage section.\n\n### Extracting styles with webpack\n\nIn your webpack configuration create a small plugin to wrap the `getCss` function:\n\n```js\nconst styleSheet = require('style-sheet/babel')\nconst { RawSource } = require('webpack-sources')\n\nconst bundleFilenamePath = 'style-sheet-bundle.css'\nclass StyleSheetPlugin {\n  apply(compiler) {\n    compiler.plugin('emit', (compilation, cb) =\u003e {\n      compilation.assets[bundleFilenamePath] = new RawSource(styleSheet.getCss())\n      cb()\n    })\n  }\n}\n```\n\nand register an instance of it in the `plugins` section of the webpack configuration:\n\n```js\n// class StyleSheetPlugin {\n// ...\n// }\n\nmodule.exports = {\n  // ...\n  module: {\n    rules: {\n      test: /\\.jsx?$/,\n      use: {\n        loader: 'babel-loader',\n        options: {\n          plugins: [styleSheet.default]\n        }\n      }\n    }\n  },\n  plugins: [\n    new StyleSheetPlugin()\n  ],\n  // ...\n}\n```\n\nRemember to also register the Babel plugin if you are using Babel via webpack.\n\nThat's it! webpack will write `bundleFilenamePath` in your public assets folder.\n\n## Advanced usage\n\nStyleSheet ships with CommonJS, ESM and UMD bundles respectively available at:\n\n* `lib/cjs`\n* `lib/esm`\n* `lib/umd`\n\nThroughout the readme we will use `lib/esm` in the examples that require you to point to individual modules manually.\n\nStyleSheet comes with a factory to generate an instance of `StyleSheet` and `StyleResolver`. The factory available at `style-sheet/lib/umd/factory` and can be used to have fine control over the style sheets creation and support unusual cases like rendering inside of iframes.\n\nMore documentation to come, please refer to the implementation in `src/factory.js` and see how it is used in `src/index.js`.\n\n## Using StyleSheet with React\n\nStyleSheet is framework agnostic but it works well with React.\n\n```jsx\nimport React from 'react'\nimport { StyleSheet, StyleResolver } from 'style-sheet'\n\nexport default ({ children }) =\u003e {\n  const className = StyleResolver.resolve([styles.root, styles.another])\n  return (\n    \u003cdiv className={className}\u003e{children}\u003c/div\u003e\n  )\n}\n\nconst styles = StyleSheet.create({\n  root: {\n    color: 'red',\n  },\n  another: {\n    color: 'green'\n  }\n})\n```\n\n### The style (`css`) prop\n\nStyleSheet provides an helper to create a custom `createElement` function that adds support for a styling prop to React. By default this prop is called `css` (but its name can be configured) and it allows you to define \"inline styles\" that get compiled to real CSS and removed from the element. These are also vendor prefixed and scoped.\n\nNote that when applying styles, `className` takes always precedence over the style prop. This allows parent components to pass styles such as overrides to children.\n\nTo use this feature you need to create an empty file in your project, name it `createElement.js` and add the following code:\n\n```jsx\nimport * as StyleSheet from 'style-sheet'\nimport setup from 'style-sheet/lib/esm/createElement'\n\nconst stylePropName = 'css'\nexport const createElement = setup(StyleSheet, stylePropName)\n```\n\nand then instruct Babel to use this method instead of the default `React.createElement`. This can be done in two ways:\n\n* Adding the `/* @jsx createElement */` at the top of every file\n\n```jsx\n/* @jsx createElement */\n\nimport React from 'react'\nimport createElement from './path/to/createElement.js'\n\nexport default ({ children }) =\u003e (\n  \u003cdiv css={{ color: 'red' }}\u003e{children}\u003c/div\u003e\n)\n```\n\n* In your Babel configuration\n\n```js\n{\n  \"plugins\": [\n    [\"@babel/plugin-transform-react-jsx\", {\n      \"pragma\": \"createElement\" // React will use style-sheet's createElement\n    }],\n    [\"style-sheet/babel\", {\n      \"stylePropName\": \"css\",\n      \"stylePropPackageName\": \"./path/to/createElement.js\"\n    }]\n  ]\n}\n```\n\nor if you use `@babel/preset-react`\n\n```js\n{\n  \"presets\": [\n    [\n      \"@babel/preset-react\",\n      {\n        \"pragma\": \"createElement\" // React will use style-sheet's createElement\n      }\n    ]\n  ],\n  \"plugins\": [\n    [\"style-sheet/babel\", {\n      \"stylePropName\": \"css\",\n      \"stylePropPackageName\": \"./path/to/createElement.js\"\n    }]\n  ]\n}\n```\n\nWhen possible, the Babel plugin will hoist and extract to .css file the style prop!\n\n## i18n\n\nStyleSheet comes with built-in support for i18n and RTL.\n\nIn order for i18n to work StyleSheet requires you to define and set an i18n manager that is an object with two properties:\n\n```js\nimport { setI18nManager } from 'style-sheet'\nconst i18nManager = {\n  isRTL: true, // Boolean\n  doLeftAndRightSwapInRTL: true // Boolean\n}\n\nsetI18nManager(i18nManager)\n```\n\nIn your app you can then toggle `isRTL` and (important) you need to re-render the application yourself i.e. `isRTL` is not a reactive property and styles don't resolve automatically when you change direction in the i18n manager. In a React application the i18n manager would likely be kept in state and consumed via context.\n\nI18n works with server side rendering and static extraction too!\n\n\n## Contributing\n\nPlease refer to the [contributing guidelines document](https://github.com/giuseppeg/contributing).\n\n### Roadmap\n\nFeel free to contact [me](https://twitter.com/giuseppegurgone) if you want to help with any of the following tasks (sorted in terms on priority/dependency):\n\n- [ ] Find a better/smaller deterministic name scheme for classes (right now it is `dss_hashedProperty-hashedValue`)\n- [ ] Consider adding support for i18n properties like `marginHorizontal`\n- [ ] Add support for `StyleSheet.createPrimitive` (or `createRule`) to generate non-atomic rules that can be used for the primitives' base styling (and avoid too many atomic classes on elements)\n\n## Credits\n\nThanks to:\n\n* [Matt Hamlin](https://twitter.com/immatthamlin) for transferring ownership of the npm package to us.\n* [Callstack.io/linaria](https://github.com/callstack/linaria/issues/242) for providing the evaluation library to extract styles to static.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiuseppeg%2Fstyle-sheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiuseppeg%2Fstyle-sheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiuseppeg%2Fstyle-sheet/lists"}