{"id":13393713,"url":"https://github.com/emotion-js/facepaint","last_synced_at":"2025-05-15T16:05:17.445Z","repository":{"id":57124899,"uuid":"107838915","full_name":"emotion-js/facepaint","owner":"emotion-js","description":"Responsive style values for css-in-js.","archived":false,"fork":false,"pushed_at":"2022-10-09T12:50:21.000Z","size":45,"stargazers_count":596,"open_issues_count":13,"forks_count":19,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-05-08T00:08:11.245Z","etag":null,"topics":["css","css-in-js","emotion","javascript"],"latest_commit_sha":null,"homepage":null,"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/emotion-js.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-22T05:03:56.000Z","updated_at":"2025-04-21T05:03:19.000Z","dependencies_parsed_at":"2022-08-31T08:20:32.626Z","dependency_job_id":null,"html_url":"https://github.com/emotion-js/facepaint","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emotion-js%2Ffacepaint","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emotion-js%2Ffacepaint/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emotion-js%2Ffacepaint/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/emotion-js%2Ffacepaint/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/emotion-js","download_url":"https://codeload.github.com/emotion-js/facepaint/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254133188,"owners_count":22020293,"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","emotion","javascript"],"created_at":"2024-07-30T17:00:59.106Z","updated_at":"2025-05-15T16:05:17.396Z","avatar_url":"https://github.com/emotion-js.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Libraries"],"sub_categories":[],"readme":"# facepaint\n\n#### Dynamic style values for css-in-js.\n\n```javascript\nimport { css } from 'emotion'\nimport facepaint from 'facepaint'\n\nconst mq = facepaint([\n  '@media(min-width: 420px)',\n  '@media(min-width: 920px)',\n  '@media(min-width: 1120px)'\n])\n\nconst myClassName = css(mq({\n  color: ['red', 'green', 'blue', 'darkorchid'],\n}))\n```\n\n## Install\n\n```bash\nnpm i facepaint -S\n```\n\n**or**\n\n```bash\nyarn add facepaint\n```\n\n## API\n\n#### facepaint `function`\n\n```javascript\nfacepaint(selectors: Array\u003cSelector\u003e) : DynamicStyleFunction\n```\n\n**Arguments**\n* *breakpoints*\n  ```javascript\n  const mq = facepaint([\n    '@media(min-width: 420px)',\n    '@media(min-width: 920px)',\n    '@media(min-width: 1120px)'\n  ])\n  ```\n\n* *options*\n  ```javascript\n  const mq = facepaint(\n    [...],\n    {\n      literal: true|false,\n      overlap: true|false\n    }\n  )\n  ```\n  - **literal** `boolean` (Default: `false`) - output should match arguments given to `facepaint` exactly\n    \n    By default, the first value in a value array is applied without a media query or selector and the rest of the values are applied as children of media queries or selectors. When `literal` is set to `true` the values given to a specific css property mapped 1:1 with the arguments provided to `facepaint`.\n    \n    Given the following:\n    \n    ```javascript\n    const mq = facepaint([\n      '@media(min-width: 420px)'\n      '@media(min-width: 920px)'\n    ], { literal: true })\n    \n    const expandedStyles = mq({\n      color: ['red', 'green']\n    })\n    ```\n    \n    The output of `expandedStyles` will be:\n    \n    ```javascript \n    { \n      '@media(min-width: 420px)': {\n        color: 'red'\n      },\n      '@media(min-width: 920px)': {\n        color: 'green'\n      }\n    }\n    ```\n    \n    The output is missing any styles on the base style object because the values are mapped to the arguments supplied to `facepaint` literally.\n    \n    \n  \n  - **overlap** `boolean` (Default: `false`) - overlap values that occur in multiple media queries or slots\n    \n    Given the following:\n    \n    ```javascript\n    const mq = facepaint([\n      '@media(min-width: 420px)'\n    ], { overlap: true })\n    \n    const expandedStyles = mq({\n      color: ['red', 'red']\n    })\n    ```\n    \n    The value of `expandedStyles` would not contain any media query breakpoints. This is an optimization to remove bytes from the final code.\n    \n    ```javascript \n    { color: 'red' }\n    ```\n    \n    vs.\n    \n    ```javascript \n    { \n      color: 'red',\n      '@media(min-width: 420px)': {\n        color: 'red'\n      }\n    }\n    ```\n    \n    The downside of enabling this option is that when attempting to overwrite the value of `color` in another style definition the expected media query will be missing. \n    \n    ```javascript\n    const style1 = css(mq({ color: ['red', 'red'] }))\n    const style2 = css({ color: 'blue' })\n    const composedStyles = css(style1, style2)\n    ```\n    \n    `style1`'s output will *NOT* contain the media query and value for red at `420px` due to the `overlap: true` optimization.\n    \n    The developer that created `composedStyles` might expect the following output.\n    \n    ```javascript \n    { \n      color: 'blue',\n      '@media(min-width: 420px)': {\n        color: 'red'\n      }\n    }\n    ```\n    \n    Due to our `overlap: true` optimization however, the final output will be the following.\n    \n    ```javascript \n    { color: 'blue' }\n    ```\n    \n    \n    \n\n**Returns**\n\n`facepaint` returns a function that can be exported and used throughout\nyour app to dynamically style based on your provided selectors.\n\n- The function accepts any number of arrays or objects as arguments.\n- Nested arrays are flattened.\n- Boolean, `undefined`, and `null` values are ignored.\n\n\n## Examples\n- [emotion](#emotion)\n- [styled-components](#styled-components)\n- [pseudo selectors](#pseudo-selectors)\n\n### emotion\n\n**[CodeSandbox Demo](https://codesandbox.io/s/lxqmwmyzql)**\n\n```javascript\nimport { css } from 'emotion'\nimport facepaint from 'facepaint'\n\nconst mq = facepaint([\n  '@media(min-width: 420px)',\n  '@media(min-width: 920px)',\n  '@media(min-width: 1120px)'\n])\n\nconst myClassName = css(mq({\n  backgroundColor: 'hotpink',\n  textAlign: 'center',\n  width: ['25%', '50%', '75%', '100%'],\n  '\u0026 .foo': {\n    color: ['red', 'green', 'blue', 'darkorchid'],\n    '\u0026 img': {\n      height: [10, 15, 20, 25]\n    }\n  }\n}))\n```\n\n**Note that the first value is considered a default value and is not a child of a media query at-rule.**\n\n**The following css is generated.**\n\n```css\n.css-rbuh8g {\n  background-color: hotpink;\n  text-align: center;\n  width: 25%;\n}\n\n@media (min-width:420px) {\n  .css-rbuh8g {\n    width: 50%;\n  }\n}\n\n@media (min-width:920px) {\n  .css-rbuh8g {\n    width: 75%;\n  }\n}\n\n@media (min-width:1120px) {\n  .css-rbuh8g {\n    width: 100%;\n  }\n}\n\n.css-rbuh8g .foo {\n  color: red;\n}\n\n@media (min-width:420px) {\n  .css-rbuh8g .foo {\n    color: green;\n  }\n}\n\n@media (min-width:920px) {\n  .css-rbuh8g .foo {\n    color: blue;\n  }\n}\n\n@media (min-width:1120px) {\n  .css-rbuh8g .foo {\n    color: darkorchid;\n  }\n}\n\n.css-rbuh8g .foo img {\n  height: 10px;\n}\n\n@media (min-width:420px) {\n  .css-rbuh8g .foo img {\n    height: 15px;\n  }\n}\n\n@media (min-width:920px) {\n  .css-rbuh8g .foo img {\n    height: 20px;\n  }\n}\n\n@media (min-width:1120px) {\n  .css-rbuh8g .foo img {\n    height: 25px;\n  }\n}\n```\n\n### styled-components\n\n```javascript\nimport styled from 'styled-components'\nimport facepaint from 'facepaint'\n\nconst mq = facepaint([\n  '@media(min-width: 420px)',\n  '@media(min-width: 920px)',\n  '@media(min-width: 1120px)'\n])\n\nconst Div = styled('div')`\n  ${mq({\n    backgroundColor: 'hotpink',\n    textAlign: 'center',\n    width: ['25%', '50%', '75%', '100%'],\n    '\u0026 .foo': {\n      color: ['red', 'green', 'blue', 'papayawhip'],\n      '\u0026 img': {\n        height: ['10px', '15px', '20px', '25px']\n      }\n    }\n  })};\n`\n\n\u003cDiv/\u003e\n```\n\n**The following css is generated.**\n\n```css\n.c0 {\n  background-color: hotpink;\n  text-align: center;\n  width: 25%;\n}\n\n.c0 .foo {\n  color: red;\n}\n\n.c0 .foo img {\n  height: 10px;\n}\n\n@media (min-width:420px) {\n  .c0 {\n    width: 50%;\n  }\n}\n\n@media (min-width:920px) {\n  .c0 {\n    width: 75%;\n  }\n}\n\n@media (min-width:1120px) {\n  .c0 {\n    width: 100%;\n  }\n}\n\n@media (min-width:420px) {\n  .c0 .foo {\n    color: green;\n  }\n}\n\n@media (min-width:920px) {\n  .c0 .foo {\n    color: blue;\n  }\n}\n\n@media (min-width:1120px) {\n  .c0 .foo {\n    color: papayawhip;\n  }\n}\n\n@media (min-width:420px) {\n  .c0 .foo img {\n    height: 15px;\n  }\n}\n\n@media (min-width:920px) {\n  .c0 .foo img {\n    height: 20px;\n  }\n}\n\n@media (min-width:1120px) {\n  .c0 .foo img {\n    height: 25px;\n  }\n}\n```\n\n## Pseudo Selectors\n\n**[CodeSandbox Demo](https://codesandbox.io/s/j5q3m3qy5)**\n\n```javascript\nimport { css } from 'emotion'\nimport facepaint from 'facepaint'\n\nconst pseudo = facepaint([':hover', ':focus', ':active'])\n\nconst myClassName = css(\n  pseudo({\n    backgroundColor: 'hotpink',\n    textAlign: 'center',\n    width: ['25%', '50%', '75%', '100%'],\n    '\u0026 .foo': {\n      color: ['red', 'green', 'blue', 'darkorchid'],\n      '\u0026 img': {\n        height: [10, 15, 20, 25]\n      }\n    }\n  })\n)\n```\n\n\n```css\n.css-1guvnfu {\n  background-color: hotpink;\n  text-align: center;\n  width: 25%;\n}\n\n.css-1guvnfu:hover {\n  width: 50%;\n}\n\n.css-1guvnfu:focus {\n  width: 75%;\n}\n\n.css-1guvnfu:active {\n  width: 100%;\n}\n\n.css-1guvnfu .foo {\n  color: red;\n}\n\n.css-1guvnfu .foo:hover {\n  color: green;\n}\n\n.css-1guvnfu .foo:focus {\n  color: blue;\n}\n\n.css-1guvnfu .foo:active {\n  color: darkorchid;\n}\n\n.css-1guvnfu .foo img {\n  height: 10px;\n}\n\n.css-1guvnfu .foo img:hover {\n  height: 15px;\n}\n\n.css-1guvnfu .foo img:focus {\n  height: 20px;\n}\n\n.css-1guvnfu .foo img:active {\n  height: 25px;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femotion-js%2Ffacepaint","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Femotion-js%2Ffacepaint","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Femotion-js%2Ffacepaint/lists"}