{"id":13395284,"url":"https://github.com/chibicode/react-functional-css-protips","last_synced_at":"2025-03-13T20:32:00.233Z","repository":{"id":151199436,"uuid":"65323956","full_name":"chibicode/react-functional-css-protips","owner":"chibicode","description":":sunglasses: Functional CSS - The Good, The Bad, and Some Protips for React.js Users","archived":true,"fork":false,"pushed_at":"2017-06-10T06:50:57.000Z","size":38,"stargazers_count":679,"open_issues_count":1,"forks_count":14,"subscribers_count":15,"default_branch":"master","last_synced_at":"2024-07-31T17:23:48.752Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"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/chibicode.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}},"created_at":"2016-08-09T19:55:41.000Z","updated_at":"2024-06-01T17:07:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"f93fe09c-1114-43e7-a334-2a39e8ef455c","html_url":"https://github.com/chibicode/react-functional-css-protips","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/chibicode%2Freact-functional-css-protips","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chibicode%2Freact-functional-css-protips/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chibicode%2Freact-functional-css-protips/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chibicode%2Freact-functional-css-protips/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chibicode","download_url":"https://codeload.github.com/chibicode/react-functional-css-protips/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243478346,"owners_count":20297238,"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":[],"created_at":"2024-07-30T17:01:49.176Z","updated_at":"2025-03-13T20:31:59.560Z","avatar_url":"https://github.com/chibicode.png","language":null,"funding_links":[],"categories":["Others","Uncategorized","Articles"],"sub_categories":["Uncategorized"],"readme":"# Functional CSS - The Good, The Bad, and Some Protips for React.js Users\n\n![](https://cloud.githubusercontent.com/assets/992008/17532105/d52e78fa-5e33-11e6-94d2-4b77b801c671.png)\n\n### UPDATE (Jun 10, 2017)\n\nI wrote this essay in mid-2016. More libraries have come out since then. As of Jun 10, 2017, **I recommend using [styled-components](https://github.com/styled-components/styled-components) or [styled-jsx](https://github.com/zeit/styled-jsx) over CSS modules.** I don't plan on updating this article, but I welcome pull requests!\n\n### Table of Contents\n\nThis repo is a Three-Act \u003cs\u003erant\u003c/s\u003e essay.\n\n- [**Prologue:** Who this document is for](#sunglasses-prologue-who-this-document-is-for-sunglasses)\n- [**Act I:** What is functional CSS and why would I want to use it?](#sunglasses-act-i-what-is-functional-css-and-why-would-i-want-to-use-it-sunglasses)\n- [**Act II**: Some downsides of using functional CSS](#sunglasses-act-ii-some-downsides-of-using-functional-css-sunglasses)\n- [**Act III**: Some ProTips on Writing Functional CSS in React](#sunglasses-act-iii-some-protips-on-writing-functional-css-in-react-sunglasses)\n  - [**ProTip 1**: Use \"virtual classes\" and document them](#v-protip-1-use-virtual-classes-and-document-them-v)\n  - [**ProTip 2**: Use CSS Modules and call them from `cn`](#v-protip-2-use-css-modules-and-call-them-from-cn-v)\n  - [**ProTip 3**: Make `cn` more powerful by integrating the `classnames` package](#v-protip-3-make-cn-more-powerful-by-integrating-the-classnames-package-v)\n- [**Epilogue**](#sunglasses-epilogue-sunglasses)\n  - [**Appendix**](#appendix)\n\n## :sunglasses: Prologue: Who this document is for :sunglasses:\n\nI've originally written this to teach functional CSS to my coworkers, but maybe you'll find it helpful too.\n\n- If you're already sold on:\n\n  1. Writing CSS in a **functional** (or [atomic](http://acss.io/)/immutable/utility-class) way and enjoy using toolkits like [Basscss](http://basscss.com) or [Tachyons](http://tachyons.io/), and\n  2. Writing front-end in **[React.js](https://facebook.github.io/react/)**,\n\n  Then skip to [**Act II**: Some downsides of using functional CSS](#sunglasses-act-ii-some-downsides-of-using-functional-css-sunglasses).\n\n- If you don't know what functional CSS is, or if you know it but aren't sold, continue reading the next section.\n\n- If you don't know React, you should learn it! I've written a [tutorial](http://reactfordesigners.com/labs/reactjs-introduction-for-people-who-know-just-enough-jquery-to-get-by/), which has received [0.3 million pageviews](https://cloud.githubusercontent.com/assets/992008/17539561/f2842d0c-5e63-11e6-9617-0068cbb5de28.png) in 1 year.\n\n---\n\n## :sunglasses: Act I: What is functional CSS and why would I want to use it? :sunglasses:\n\nThis example is [taken](http://tachyons.io/components/collections/product-card/index.html) from [Tachyons](http://tachyons.io/), one of the popular functional CSS toolkits. Consider this \u003cs\u003ecat\u003c/s\u003e card:\n\n\u003cimg width=\"270\" alt=\"\" src=\"https://cloud.githubusercontent.com/assets/992008/17534567/9ca18760-5e3e-11e6-8609-70ac771a618e.png\"\u003e\n\nIn functional CSS (using [Tachyons](http://tachyons.io/)), you'd write HTML like this:\n\n```html\n\u003carticle class=\"br2 ba dark-gray b--black-10 mv4 w-100 w-50-m w-25-l mw5 center\"\u003e\n  \u003cimg src=\"http://placekitten.com/g/600/300\" class=\"db w-100 br2 br--top\" alt=\"kitty\"\u003e\n  \u003cdiv class=\"pa2 ph3-ns pb3-ns\"\u003e\n    \u003cdiv class=\"dt w-100 mt1\"\u003e\n      \u003cdiv class=\"dtc\"\u003e\n        \u003ch1 class=\"f5 f4-ns mv0\"\u003eCat\u003c/h1\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"dtc tr\"\u003e\n        \u003ch2 class=\"f5 mv0\"\u003e$1,000\u003c/h2\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n    \u003cp class=\"f6 lh-copy measure mt2 mid-gray\"\u003e...\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/article\u003e\n```\n\nAbove HTML uses the following CSS classes that are built into Tachyons.\n\n```css\n.ba { border-style: solid; border-width: 1px; }\n.b--black-10 { border-color: rgba(0, 0, 0, .1); }\n.br2 { border-radius: .25rem; }\n.br--top { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }\n.db { display: block; }\n.dt { display: table; }\n.dtc { display: table-cell; }\n.lh-copy { line-height: 1.6; }\n.mw5 { max-width: 16rem; }\n.w-100 { width: 100%; }\n.dark-gray { color: #333; }\n.mid-gray { color: #555; }\n.pa2 { padding: .5rem; }\n.mt1 { margin-top: .25rem; }\n.mt2 { margin-top: .5rem; }\n.mv0 { margin-top: 0; margin-bottom: 0; }\n.mv4 { margin-top: 2rem; margin-bottom: 2rem; }\n.tr { text-align: right; }\n.f5 { font-size: 1rem; }\n.f6 { font-size: .875rem; }\n.measure { max-width: 30em; }\n.center { margin-right: auto; margin-left: auto; }\n\n@media screen and (min-width: 30em) {\n  .pb3-ns { padding-bottom: 1rem; }\n  .ph3-ns { padding-left: 1rem; padding-right: 1rem; }\n  .f4-ns { font-size: 1.25rem; } }\n@media screen and (min-width: 30em) and (max-width: 60em) {\n  .w-50-m { width: 50%; } }\n@media screen and (min-width: 60em) {\n  .w-25-l { width: 25%; } }\n```\n\n### Did you think: \"This looks like a *terrible* idea\"?\n\nI did too, until I actually started using functional CSS on my company's production code, and the *maintainability of our frontend went up by 10x* (rough estimate). Why? The answer is simple:\n\n- If you use functional CSS, **when you add something new to a page, you'll rarely write any new CSS.** You can build most of what you want by composing these small CSS classes.\n- This is a sharp contrast to using traditional \"semantic CSS\", where you'll add new classes like `shopping-cart__item--selected` **every time** you add something new.\n- Because you'll write CSS less, your overall CSS size will be small. That's a win for your users (faster load time), but also a win for developers.\n  - Why? Because developers need to **look at existing CSS** and ask themselves: *\"Is there any class I can reuse?\"* - but this gets harder as the size of CSS grows.\n\n### On *not* writing new CSS\n\nThe last point is important. Look at the CSS of a large app you're writing, right now. Does it resemble something like below?\n\n```css\n/* utils.css */\n/* --------- */\n.left {\n  float: left!important;\n}\n/* 50 lines later ... */\n.left-max-scr1,\n.left-max-scr2,\n.left-max-scr3,\n.left-only-scr1 {\n  float: left;\n}\n\n/* nav.css */\n/* ------- */\n.header-nav-container .header-nav-list {\n  float: left;\n}\n/* 50 lines later... */\n.CA .header-nav-list.second {\n  float: left;\n}\n/* 50 lines later... */\n#nav.challenger-a .submenu-3col li,\n#nav.challenger-a .submenu-3col li {\n  float: left;\n}\n\n/* ie.css */\n/* ------ */\n.ie6 #footer-content .flex-control-nav li a,\n.ie7 #footer-content .flex-control-nav li a,\n.ie8 #footer-content .flex-control-nav li a {\n  float: left;\n}\n```\n\nOr take a look at [GitHub's CSS](https://gist.github.com/mrmrs/786241f0a5fade0324e2), which contains 300+ CSS rules that just say `display: none`.\n\nFor GitHub's credit, their code is likely generated by SCSS, so they didn't *actually* write 300+ `display: none`'s. But as a long time SCSS user, I'd say that there's not much preprocessors can do to prevent us from writing more CSS.\n\nBy the way, the code above is actually from an excellent article **[CSS and Scalability](http://mrmrs.io/writing/2016/03/24/scalable-css/)**, written by Adam Morse, the author of Tachyons. He claims (emphasis added):\n\n\u003e If you’re going to build a new component, or change a piece of UI in your app - what do you do? I don’t know anyone that reads all the available css in the app to see if there is something they can reuse. **Who has time to read thousands of lines of code before they start working!?** Even if people do have the time, I have not found that this is their first instinct on how to get going. I don’t blame them.\n\n\u003e **Even if you did read all of the available css and stumbled upon some code that you think might be reusable - what if someone edits it later? If you are starting from the assumption that your css isn't reusable, your first instinct is to write new css. But most likely you aren't creating a new classification of visual styles.** In my experience it is likely that you are replicating visual styles that already exist.\n\n\u003e ... Outside of some brand specific background-images, gradients, and colors etc., **the overwhelming majority of css you would need for your site has already been written.**\n\u003e\n\u003e ... **The real way to scale css, is to stop writing css.** Abstract out the things you use most and move to a multi-class pattern where you compose visual patterns in your html. You might be amazed at how quickly your team starts to move.\n\nI strongly encourage you to [read all of Adam's words](http://mrmrs.io/writing/2016/03/24/scalable-css/). But I know you probably won't. Fine. I'll copy-paste some more:\n\n\u003e There are a number of suggested 'best practices' around how sass/less/stylus etc. will help you build maintainable css. How mixins can make your code more DRY. How extends will keep your markup clean and pretty to look at. **How BEM will make your code so perfect you want to cry.**\n\n\u003e **But what is reality?** What actually gets shipped to production? What do all of these tips and tricks do to our production css? How does it affect the whole team? More important, how are your end users affected?\n\n\u003e **When it comes to designing and shipping products I like to think about reality.** Which can be challenging sometimes... But, if you don't accurately assess where you currently are and what your reality is, it can be pretty tough to figure out what your problems are.\n\nOk, I'm satisfied. Let's move on.\n\n### So you'll write less CSS, but isn't writing HTML harder now?\n\nWhen you use these small classes, it'll be harder to write HTML code **IF** you don't know which classes to use. But here's the key part: popular functional CSS toolkits like [Basscss](http://basscss.com/) and [Tachyons](http://tachyons.io/) are **extremely well documented**. Just take a look at their documentation:\n\n- [Basscss Docs](http://www.basscss.com/)\n- [Tachyons Docs](http://tachyons.io/docs/)\n\nAnd both Basscss and Tachyons have illustrative examples of building larger components by combining small classes. Here's how you build a panel using Basscss classes, according to their official docs.\n\n![](https://cloud.githubusercontent.com/assets/992008/17543262/2e5cd03e-5e84-11e6-86bb-7e65f56b0d2c.png)\n\nOnce you familiarize yourself with ~50% of the feature set, you'll notice yourself shipping things **really fast**.\n\nAs for documentation, the flip side is also true. If you roll your own functional CSS library (or add tons of new classes to extend Basscss/Tachyons), but **don't document them**, that's a recipe for a nightmare. In other words, **documentation (of small CSS classes) is what makes functional CSS work.**\n\n### What about code reuse for HTML?\n\nLet's return to the Tachyons cat example:\n\n\u003cimg width=\"270\" alt=\"\" src=\"https://cloud.githubusercontent.com/assets/992008/17534567/9ca18760-5e3e-11e6-8609-70ac771a618e.png\"\u003e\n\n```html\n\u003carticle class=\"br2 ba dark-gray b--black-10 mv4 w-100 w-50-m w-25-l mw5 center\"\u003e\n  \u003cimg src=\"http://placekitten.com/g/600/300\" class=\"db w-100 br2 br--top\" alt=\"kitty\"\u003e\n  \u003cdiv class=\"pa2 ph3-ns pb3-ns\"\u003e\n    \u003cdiv class=\"dt w-100 mt1\"\u003e\n      \u003cdiv class=\"dtc\"\u003e\n        \u003ch1 class=\"f5 f4-ns mv0\"\u003eCat\u003c/h1\u003e\n      \u003c/div\u003e\n      \u003cdiv class=\"dtc tr\"\u003e\n        \u003ch2 class=\"f5 mv0\"\u003e$1,000\u003c/h2\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n    \u003cp class=\"f6 lh-copy measure mt2 mid-gray\"\u003e...\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/article\u003e\n```\n\nSuppose that somewhere else on your app, you'll need to have a card similar to above, but the card features a dog instead. You'll need to:\n\n- Copy-paste above code\n- Replace the photo, name, price, and description\n- Keep all of the classes.\n\nThat sounds brittle and not very DRY.\n\nInstead, you should be using some sort of **HTML templates**. Rails has partials and Django has templates for this purpose. In React or Angular, you can create a component. Here's a React example:\n\n```js\nconst ItemCard = ({ name, price, image, description, alt }) =\u003e (\n  \u003carticle className=\"br2 ba dark-gray b--black-10 mv4 w-100 w-50-m w-25-l mw5 center\"\u003e\n    \u003cimg src={image} className=\"db w-100 br2 br--top\" alt={alt}\u003e\n    \u003cdiv className=\"pa2 ph3-ns pb3-ns\"\u003e\n      \u003cdiv className=\"dt w-100 mt1\"\u003e\n        \u003cdiv className=\"dtc\"\u003e\n          \u003ch1 className=\"f5 f4-ns mv0\"\u003e{name}\u003c/h1\u003e\n        \u003c/div\u003e\n        \u003cdiv className=\"dtc tr\"\u003e\n          \u003ch2 className=\"f5 mv0\"\u003e{price}\u003c/h2\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n      \u003cp className=\"f6 lh-copy measure mt2 mid-gray\"\u003e{description}\u003c/p\u003e\n    \u003c/div\u003e\n  \u003c/article\u003e\n)\n```\n\nAnd **you'd reuse the component instead of reusing HTML directly**:\n\n```js\n\u003cItemCard name='Cat' price='$1,000' image='...' description='...' alt='...' /\u003e\n\u003cItemCard name='Dog' price='$2,000' image='...' description='...' alt='...' /\u003e\n```\n\nIn other words, **template/component system (for HTML markup) is what makes functional CSS great.**\n\n### But those CSS classes still look too cryptic to me.\n\nThen try [Basscss](http://www.basscss.com/). Its classes are a bit more readable than Tachyons's.\n\n```html\n\u003cdiv class=\"inline\"\u003einline\u003c/div\u003e\n\u003cdiv class=\"inline-block\"\u003einline-block\u003c/div\u003e\n\u003ca href=\"#\" class=\"block\"\u003eblock\u003c/a\u003e\n\u003cdiv class=\"table\"\u003e\n  \u003cdiv class=\"table-cell\"\u003etable-cell\u003c/div\u003e\n  \u003cdiv class=\"table-cell\"\u003etable-cell\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv class=\"clearfix\"\u003e\n  \u003cdiv class=\"left\"\u003efloat left\u003c/div\u003e\n  \u003cdiv class=\"right\"\u003efloat right\u003c/div\u003e\n\u003c/div\u003e\n```\n\n### Ok fine, I'm sold.\n\nGreat! Here are some more articles on functional CSS:\n\n- [Building and shipping functional CSS](https://blog.colepeters.com/building-and-shipping-functional-css/) by Cole Peters\n- [Rationalizing Functional CSS](https://marcelosomers.com/writing/rationalizing-functional-css/) by Marcelo Somers\n- [Functional Programming, CSS, and your sanity](http://www.jon.gold/2015/07/functional-css/) by Jon Gold\n\nAnd here are some real-world styleguides that use functional CSS:\n\n- [Solid, Buzzfeed's Functional CSS Style Guide](http://solid.buzzfeed.com/) ([Blog Post](https://medium.com/buzzfeed-design/introducing-solid-1c16b1bf4868))\n- [Marvel's Functional CSS Style Guide](https://marvelapp.com/styleguide/) ([Blog Post](https://blog.marvelapp.com/the-marvel-styleguide/))\n\n### Do you use [Basscss](http://basscss.com/) or [Tachyons](http://tachyons.io/)? How do I customize the built-in styles?\n\nI use both. I encourage you to learn [Basscss](http://basscss.com/) first because its class names tend to be easier to understand. But I like how [Tachyons](http://tachyons.io/) have first-class responsive design support for all the built-in classes, [like this](http://tachyons.io/docs/typography/text-align/):\n\n```css\n@custom-media --breakpoint-not-small screen and (min-width: 48em);\n@custom-media --breakpoint-medium screen and (min-width: 48em) and (max-width: 64em);\n@custom-media --breakpoint-large screen and (min-width: 64em);\n\n.tl  { text-align: left; }\n.tr  { text-align: right; }\n.tc  { text-align: center; }\n\n@media (--breakpoint-not-small) {\n  .tl-ns  { text-align: left; }\n  .tr-ns  { text-align: right; }\n  .tc-ns  { text-align: center; }\n}\n\n@media (--breakpoint-medium) {\n  .tl-m  { text-align: left; }\n  .tr-m  { text-align: right; }\n  .tc-m  { text-align: center; }\n}\n\n@media (--breakpoint-large) {\n  .tl-l  { text-align: left; }\n  .tr-l  { text-align: right; }\n  .tc-l  { text-align: center; }\n}\n```\n\nSo if you want to center align something on a mobile screen, but use left align on bigger screens, you'd write:\n\n```html\n\u003cspan class='tc tl-ns'\u003e...\u003c/span\u003e\n```\n\nAs of this writing, [responsive utilities are available on Basscss as addons](https://github.com/basscss/addons).\n\n#### Notes on Customizing\n\nThe new CSS variables used in both Basscss and Tachyons (like `var(--name)` or `@custom-media`) can be customized by using [PostCSS](https://github.com/postcss/postcss) with [postcss-cssnext](https://github.com/MoOx/postcss-cssnext) plugin. If you're using [Webpack](https://webpack.github.io/) to load your React code, use [postcss-loader](https://github.com/postcss/postcss-loader) with [postcss-import](https://github.com/postcss/postcss-loader#integration-with-postcss-import).\n\nYou can learn more about the new CSS features [here](http://cssnext.io/features/) and PostCSS [here](http://cssnext.io/postcss/).\n\nAlso, sometimes Basscss and Tachyons don't allow customizations via CSS variables:\n\n```css\n/* Tachyons src/_type-scale.css */\n.f1 { font-size: 3rem; }\n.f2 { font-size: 2.25rem; }\n.f3 { font-size: 1.5rem; }\n.f4 { font-size: 1.25rem; }\n.f5 { font-size: 1rem; }\n.f6 { font-size: .875rem; }\n```\n\nIn that case, **copy the file** you want to customize, **change the values** (but not class names), and **load the new file** instead of the original.\n\n```css\n/* new-tachyons-import.css */\n/* load everything tachyons.css is importing, but swap the customized ones */\n@import ...;\n@import 'tachyons/src/_text-transform';\n@import 'customized-type-scale';\n@import 'tachyons/src/_utilities';\n@import ...;\n```\n\nFinally, I **don't** recommend writing a functional CSS library of your own **unless** you're willing to document most of the classes extensively.\n\nSimilarly, if you're going to **extend** (not customize) Basscss/Tachyons by adding more small classes, document the ones you add, because otherwise you'll end up adding multiple functional classes that do the same thing.\n\n---\n\n## :sunglasses: Act II: Some downsides of using functional CSS :sunglasses:\n\nFunctional CSS isn't perfect, however. Consider a design where, buttons, tabs, and headings all have text styles that look like this:\n\n![](https://cloud.githubusercontent.com/assets/992008/17548431/c116cba2-5ea0-11e6-90fa-f4b517bef37f.png)\n\n(1) They're in `uppercase`, (2) use San Francisco font as `font-family`, and (3) have some `letter-spacing`. In functional CSS, you'd write:\n\n```html\n\u003cspan class='uppercase font-san-francisco letter-spacing-1 ...'\u003e...\u003c/span\u003e\n```\n\nAnd buttons, tabs, and headings are each likely to be written as a component, like so:\n\n```js\n// Button.js - button tag, blue font\nconst Button = (...) =\u003e \u003cbutton className='blue uppercase font-san-francisco letter-spacing-1 ...'\u003e\n  ...\n\u003c/button\u003e\n\n// Tab.js - a tag, gray font\nconst Tab = (...) =\u003e \u003ca className='gray uppercase font-san-francisco letter-spacing-1 ...'\u003e\n  ...\n\u003c/a\u003e\n\n// Heading.js - h2 tag, black, large font\nconst Heading = (...) =\u003e \u003ch2 className='black font-h1 uppercase font-san-francisco letter-spacing-1 ...'\u003e\n  ...\n\u003c/h2\u003e\n```\n\nNow, suppose that a designer comes and says that (1) `font-family` should now be Futura, (2) the text should be in regular case and (3) have no `letter-spacing`.\n\n![](https://cloud.githubusercontent.com/assets/992008/17548450/d222ac40-5ea0-11e6-872e-fac447088760.png)\n\nThis will require you to replace `uppercase font-san-francisco letter-spacing-1` with `font-futura` in each of Button.js, Tab.js, and Heading.js.\n\n### The \"Find-and-Replace\" Problem\n\nThe above **\"Find-and-Replace\"** operation would be easy **IF** each file uses the same ordering of classes:\n\n```js\n// Must be in this exact order for Button.js, Tab.js and Heading.js\nclassName='... uppercase font-san-francisco letter-spacing-1'\n```\nBut that leaves a lot of room for error. And this is only changing the same 3 classes in 3 different files. What if the codebase is much bigger? What if we have to do more complex Find-and-Replace?\n\nTo me, this **\"Find-and-Replace\"** problem, or batch-modifying similar styles across **multiple** components (templates) is one of the challenging things when using functional CSS **in practice**.\n\n[Marcelo Somers writes](https://marcelosomers.com/writing/rationalizing-functional-css/): (emphasis added):\n\n\u003e It's wonderful the first time you create a component, but updating styles in an existing system can be a complicated mess of find and replace and other keyboard shortcuts.\n\u003e\n\u003e ... **[Using find and replace] presumes you created multiple of the same \"components\" by putting the utility classes in the same order, especially when doing find and replace across multiple pages.** Otherwise, there is no easy way to search across your entire application to find where similar components were implemented.\n\u003e\n\u003e This might be my single biggest concern about implementing functional CSS in a large app. Just imagine a standard \"box\" component made up of 7-10 utility classes. If you wanted to change the font size inside all the boxes, you'd need find every instance across your app and update each one manually.\n\u003e\n\u003e **That leaves a lot of room for error.**\n\nHe suggests a \"possible fix,\" where you'd add \"a fake class\" that has no effect but is just a marker for find-and-replace:\n\n```html\n\u003cdiv class=\"box-component flex p2 bg-blue white h4 bold\"\u003e\n  The .box-component class wouldn't actually style anything, it would merely be a search key for finding instances where the box component gets used.\n\u003c/div\u003e\n```\n\nBut again, you might forget to add this fake class, and then you'd be screwed.\n\n### Styles might diverge, and fixing them can be challenging\n\nIf Find-and-Replace fails, your page might end up in a state like this:\n\n![](https://cloud.githubusercontent.com/assets/992008/17549227/20113d2e-5ea4-11e6-851a-2522f01bf80b.png)\n\nFixing this can be painful, because now you'll need to modify different classes on each file. On Button.js, you need to change `font-san-francisco` to `font-futura`. On Tab.js, you need to remove `uppercase`. On Heading.js, you need to remove `letter-spacing-1`.\n\nThat's not too bad with if you can visually examine each component and figure out what's wrong. But there's no easy way to point that out by just looking at the code. And remember: we're dealing with just 3 classes across 3 files.\n\nMoreover, with functional CSS, **you'll likely end up in a state like above when you're writing new components.**\n\nIf ideas like \"semi-important texts (1) are in `uppercase`, (2) use San Francisco as `font-family`, and (3) have some `letter-spacing`.\" are not represented/documented anywhere, and **a dev has to make a decision** without a designer (which happens **often** in practice), you'll end up in a state like earlier.\n\nUsing components/templates to reuse markup will help, but you can't componentize everything. Sometimes different components need to use similar styles.\n\n### You'd still have to write CSS from time to time\n\nIf some component *must* have a height of 178px and be absolutely positioned from the bottom at 12px, then you **don't** want to make new classes called `height-178` and `bottom-12`. They aren't reusable and probably won't be documented. This goes against the philosophies of functional CSS.\n\nIn this case, you should just use regular CSS classes which **augment** functional classes:\n\n```js\n// some-box is NOT a functional class - it'll look like this:\n//\n// .some-box {\n//   height: 178px;\n//   bottom: 12px;\n// }\n\u003cdiv class='p2 absolute some-box'\u003e...\u003c/div\u003e\n```\n\nBut again, how should we write regular CSS? Should we just use [BEM](https://css-tricks.com/bem-101/) again? Or write [CSS in JS (inline styles)](https://speakerdeck.com/vjeux/react-css-in-js)?\n\nOne of the downsides of using inline styles is that the support for pseudo selectors (e.g. `:hover`) and `@media` queries is poor. Libraries like [Radium](https://github.com/FormidableLabs/radium) are designed to solve this, but Radium had [some critical bugs](https://github.com/FormidableLabs/radium/issues/367) that don't seem to have a good solution.\n\nOr should we try the new kid on the block, [CSS Modules](https://github.com/css-modules/css-modules)?\n\n\u003ca href=\"https://twitter.com/mxstbr/status/756769255111192576\"\u003e\u003cimg width=\"482\" alt=\"\" src=\"https://cloud.githubusercontent.com/assets/992008/17598955/bf5f3620-5fb1-11e6-8c5d-eb752a891b20.png\"\u003e\u003c/a\u003e\n\nI think part of a problem is that React offers many different ways to write regular CSS. You should probably pick one and run with it. But which one should you pick?\n\n#### Coming Up Next...\n\nIn summary, the main problems I encountered with functional CSS are:\n\n- The \"Find-and-Replace\" problem, and\n- Still having to write regular CSS (which isn't too bad).\n\nIn the next act, I'll present my take on solving these problems.\n\n---\n\n## :sunglasses: Act III: Some ProTips on Writing Functional CSS in React :sunglasses:\n\nI spent some time thinking about how these problems can be solved. Here are my initial thoughts. They are pretty experimental and **not yet** battle tested. I'll update this document after I try these experiments on production for several months.\n\nAlso note: **these protips are React.js specific.**\n\n### :v: ProTip 1: Use \"virtual classes\" and document them :v:\n\n**A virtual class is a class which gets converted into a set of functional CSS classes at runtime.** The name is inspired by React's virtual DOM.\n\nLet's recall our previous example, where some texts (1) are in `uppercase`, (2) use San Francisco font as `font-family`, and (3) have some `letter-spacing`.\n\n![](https://cloud.githubusercontent.com/assets/992008/17548431/c116cba2-5ea0-11e6-90fa-f4b517bef37f.png)\n\nInstead of writing `uppercase font-san-francisco letter-spacing-1` like we did before:\n\n```js\nconst Button = (...) =\u003e \u003cbutton className='blue uppercase font-san-francisco letter-spacing-1 ...'\u003e\n  ...\n\u003c/button\u003e\n\nconst Tab = (...) =\u003e \u003ca className='gray uppercase font-san-francisco letter-spacing-1 ...'\u003e\n  ...\n\u003c/a\u003e\n\nconst Heading = (...) =\u003e \u003ch2 className='black font-h1 uppercase font-san-francisco letter-spacing-1 ...'\u003e\n  ...\n\u003c/h2\u003e\n```\n\nYou'd write a virtual class called `-text-style-emphasis`:\n\n```js\n'blue -text-style-emphasis'\n'gray -text-style-emphasis'\n'black font-h1 -text-style-emphasis'\n```\n\n**Virtual classes are prefixed with a hyphen by convention, so it's easier to spot them.**\n\nThen, **use `cn`** (short for \"class name\") helper function on `className`, which converts `-text-style-emphasis` to `uppercase font-san-francisco letter-spacing-1` at runtime:\n\n```js\nimport cn from '...'\n\nconst Button = (...) =\u003e \u003cbutton className={cn('blue -text-style-emphasis ...')}\u003e\n  ...\n\u003c/button\u003e\n\nconst Tab = (...) =\u003e \u003ca className={cn('gray -text-style-emphasis ...')}\u003e\n  ...\n\u003c/a\u003e\n\nconst Heading = (...) =\u003e \u003ch2 className={cn('black font-h1 -text-style-emphasis ...')}\u003e\n  ...\n\u003c/h2\u003e\n```\n\n#### The `cn` function and virtual classes\n\nThe `cn` function will convert pre-defined virtual classes to functional classes. Here's a simple implementation:\n\n```js\n// cn.js\n\n// A mapping from virtual class -\u003e functional class\nconst virtualToFunctional = {\n  '-text-style-emphasis': 'uppercase font-san-francisco letter-spacing-1'\n  // ...\n}\n\nfunction convertVirtualClassnames (classNames) {\n  return classNames.split(' ').map((className) =\u003e (\n    // If mapping exists, use that. Else leave it as is\n    virtualToFunctional[className] || className\n  )).join(' ')\n}\n\n// This becomes \"cn\"\nexport default convertVirtualClassnames\n```\n\nYou can implement a version which supports **recursive** converting, like the one below.\n\n```js\n// cn.js\nconst virtualToFunctional = {\n  '-virtual-class-a': '...',\n  // One virtual class can reference another virtual class\n  '-virtual-class-b': '... -virtual-class-a'\n}\n\nfunction convertVirtualClassnames (classNames) {\n  return classNames.split(' ').map((className) =\u003e (\n    // Recursively convert.\n    // Also return both functional and virtual classes\n    virtualToFunctional[className]\n    ? `${convertVirtualClassnames(virtualToFunctional[className])} ${className}`\n    : className\n  )).join(' ')\n}\n\nexport default convertVirtualClassnames\n```\n\nNote that the version above leaves original virtual classes untouched rather than removing them, which might be better for debugging from your browser. Because virtual classes are prefixed with a hyphen by convention, you can easily tell which classes are virtual vs functional from your Chrome/etc DevTools.\n\n#### What problem do virtual classes solve?\n\n**Virtual classes solve the \"Find-and-Replace\" problem** which I illustrated earlier.\n\n![](https://cloud.githubusercontent.com/assets/992008/17548450/d222ac40-5ea0-11e6-872e-fac447088760.png)\n\nInstead of finding and replacing multiple utility classes, you can just modify the virtual to functional mapping, or change virtual classes used on markup.\n\nIf virtual classes are well documented (which I'll cover next), they can force developers to build components with consistent styles and avoid a mess like this:\n\n![](https://cloud.githubusercontent.com/assets/992008/17549227/20113d2e-5ea4-11e6-851a-2522f01bf80b.png)\n\nVirtual classes also make HTML slightly easier to read without adding any new CSS code.\n\nOne downside of virtual classes is that you'd have to call `cn` every time for `className`, but this is actually not too bad - I'll explain why on the next ProTip.\n\n#### Build a living style guide for virtual classes\n\n**Try to build a living style guide for every virtual class** - if you can't do that, then don't write a virtual class. Documentation is **crucial**, because that's how those virtual classes get reused.\n\nLet's say that you write virtual classes called `-row-with-gutter-1` and `-col-with-gutter-1`, which can be used to build a grid system with gutters. And they get converted to Basscss classes. These might not be the best use of virtual classes, but let's ignore that for now.\n\n```js\nconst virtualToFunctional = {\n  '-row-with-gutter-1': 'clearfix mxn1',\n  '-col-with-gutter-1': 'px1'\n}\n```\n\nNext, you'd want to generate a living styleguide like this. I'll show you the code next.\n\n![](https://cloud.githubusercontent.com/assets/992008/17566510/8a04a544-5ef0-11e6-946e-e6056e0afda4.png)\n\n#### The Styleguide component: Usage\n\nThe above style guide is generated from this `Styleguide` component:\n\n```js\n\u003cStyleguide\n  title='Grid with Gutters'\n  classnames={['-row-with-gutter-1', '-col-with-gutter-1']}\n  SampleCode={({ cnProxy, Placeholder }) =\u003e (\n    \u003cdiv className={cnProxy('-row-with-gutter-1')}\u003e\n      \u003cdiv className={cnProxy('-col-with-gutter-1 col col-6')}\u003e\n        \u003cPlaceholder\u003eColumn with Gutter 1\u003c/Placeholder\u003e\n      \u003c/div\u003e\n      \u003cdiv className={cnProxy('-col-with-gutter-1 col col-6')}\u003e\n        \u003cPlaceholder\u003eColumn with Gutter 1\u003c/Placeholder\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n  )} /\u003e\n```\n\n`Styleguide` takes three parameters:\n\n- `title` is the section title.\n- `classnames` is the list of virtual classes.\n- `SampleCode` is a React component definition, which takes `cnProxy` and `Placeholder` as props, and renders some HTML that illustrates a use of these virtual classes. Use `cnProxy` instead of `cn`, and `Placeholder` as placeholders in HTML.\n\n#### The Styleguide component: Implementation (first half)\n\nHere's the first half of the code for `Styleguide`, with comments. This is the simple part.\n\n```js\nimport cn from '...'\n\nconst Styleguide = ({ title, classnames, SampleCode }) =\u003e\n  \u003cdiv\u003e\n    \u003ch2\u003e{title}\u003c/h2\u003e\n    \u003cdiv className='mb2'\u003e\n      \u003cul\u003e\n        {/* For each virtual class name in classnames,\n            show what functional classes they're converted to */}\n        {\n          classnames.map((classname) =\u003e (\n            \u003cli key={classname}\u003e\n              \u003ccode\u003e{classname}\u003c/code\u003e → \u003ccode\u003e{cn(classname)}\u003c/code\u003e\n            \u003c/li\u003e\n          ))\n        }\n      \u003c/ul\u003e\n    \u003c/div\u003e\n    \u003cdiv className='border mb2'\u003e\n      {/* Render SampleCode by using cn for cnProxy and\n          a simple component to display placeholders */}\n      \u003cSampleCode\n        cnProxy={cn}\n        Placeholder={\n          ({ children }) =\u003e\n            \u003cdiv style={{ background: '#eee', borderColor: '#ccc' }} className='p2 border'\u003e\n              {children}\n            \u003c/div\u003e\n        } /\u003e\n    \u003c/div\u003e\n    ...\n  \u003c/div\u003e\n```\n\nThe above code renders this:\n\n![](https://cloud.githubusercontent.com/assets/992008/17567069/b2a21ed0-5ef2-11e6-8a23-a618beb92ece.png)\n\n#### The Styleguide component: Implementation (second half)\n\nThe second half of `Styleguide` code looks like this:\n\n```js\nimport ...\nimport { renderToStaticMarkup } from 'react-dom/server'\n// You need to install this using `npm install`\nimport { html } from 'js-beautify'\n\nconst Styleguide = ({ title, classnames, SampleCode }) =\u003e\n  \u003cdiv\u003e\n    ...\n    \u003cpre\u003e\n      {(() =\u003e {\n        // First, create a SampleCode component instance.\n        // - Instead of using `cn` for `cnProxy`,\n        //   make a simple function which appends __cn__ to class names.\n        // - Placeholder component just returns an empty div.\n        const sampleCode =\n          \u003cSampleCode\n            cnProxy={x =\u003e `__cn__${x}`}\n            Placeholder={() =\u003e \u003cdiv /\u003e} /\u003e\n\n        // Render the component.\n        const renderedHtml = renderToStaticMarkup(sampleCode)\n\n        // Indent the rendered result.\n        const renderedHtmlIndented = html(renderedHtml, { indent_size: 2 })\n\n        // Then, replace\n        //   class=\"__cn__...\"\n        // in the rendered string with:\n        //   className={cn('...')}\n        // and replace\n        //   \u003cdiv\u003e\u003c/div\u003e\n        // in the rendered string with:\n        //   ...\n        const renderedHtmlCleaned =\n          renderedHtmlIndented\n            .replace(/class=\"__cn__([^\"]+)\"/g, 'className={cn(\\'$1\\')}')\n            .replace(/\u003cdiv\u003e\u003c\\/div\u003e/g, '...')\n\n        // Return the rendered string.\n        return renderedHtmlCleaned\n      })()}\n    \u003c/pre\u003e\n  \u003c/div\u003e\n```\n\nThe above code renders this:\n\n![](https://cloud.githubusercontent.com/assets/992008/17567814/c7eeb9d0-5ef5-11e6-98d2-2a770c53f0d4.png)\n\nNote: if you want to enable syntax highlighting like I did, you can use [Prism](https://github.com/tomchentw/react-prism), which supports JSX well.\n\n#### ProTip 1 Conclusion\n\n- Use virtual classes, which gets converted to functional class names on render.\n- Write a mapping from virtual classes to functional classes, and implement a `cn` helper which does the translation. Then call `cn` on `className`.\n- Virtual classes solve the \"Find-and-Replace\" problem which can happen often when writing functional CSS.\n- Make it easy to generate a living style guide for virtual classes.\n\n### :v: ProTip 2: Use CSS Modules and call them from `cn` :v:\n\nYou'd still have to write regular CSS (or inline styles) when functional classes don't cut it. Example I wrote earlier:\n\n\u003e If some component *must* have a height of 178px and be absolutely positioned from the bottom at 12px, then you **don't** want to make new classes called `height-178` and `bottom-12`.\n\nReact offers many ways to write regular CSS. After trying many of them, **I concluded that [CSS modules](https://github.com/css-modules/css-modules) are the way to go**.\n\n#### UPDATE (Jun 10, 2017)\n\nI wrote this essay in mid-2016. More libraries have come out since then. As of Jun 10, 2017, **I recommend using [styled-components](https://github.com/styled-components/styled-components) or [styled-jsx](https://github.com/zeit/styled-jsx) over CSS modules.** I don't plan on updating this article, but I welcome pull requests!\n\n#### What are CSS modules?\n\nIf you don't know what CSS modules are, here's an excellent introductory post: [What are CSS Modules and why do we need them?](https://css-tricks.com/css-modules-part-1-need/)\n\nCSS modules solve one problem: **global namespace collision.** By using CSS Modules, you can write CSS like this:\n\n```css\n/* header.css */\n.headerImage {\n  background-image: url(...);\n  ...\n}\n```\n\nThen, **load that CSS file from JS as an object, whose keys are the class names**:\n\n```js\n// Header.js\n\n// Load CSS into JS as a variable - yes, that's possible with CSS modules!\nimport styles from './header.css'\n\nconst Header = () =\u003e {\n  ...\n  {/* Then use class name \"headerImage\" as a key */}\n  \u003cdiv className={styles.headerImage}\u003e\n    ...\n  \u003c/div\u003e\n  ...\n}\n```\n\nAnd it generates a unique class name and a corresponding style declaration when React is rendered:\n\n```html\n\u003cstyle\u003e\n  ._styles__headerImage_309571057 {\n    background-image: url(...);\n    ...\n  }\n\u003c/style\u003e\n\n...\n\n\u003cdiv class='styles__headerImage_309571057'\u003e\n  ...\n\u003c/div\u003e\n```\n\nBy using CSS modules, you can name CSS classes whatever you want and don't need to worry about them colliding with some other classes that are written in the past or will be written in the future.\n\nAlso, because you load CSS files from JS files, if those JS files are not loaded, then the corresponding CSS won't be loaded. This can cut down the CSS size when you use [Webpack's code splitting feature](https://webpack.github.io/docs/code-splitting.html).\n\nThese are the reasons why I think CSS modules are much better than plain-old BEM.\n\n**How to use**: Webpack's CSS loader supports CSS modules, so [read the documentation](https://github.com/webpack/css-loader). CSS modules also work on server-side rendering: use `css-loader/locals` instead of `style-loader!css-loader` on server-side webpack config, and [extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin) on client-side webpack config for production.\n\n#### Side note: Alternatives\n\nI spent a good amount of time trying out Khan Academy's [aphrodite](https://github.com/Khan/aphrodite), an inline styles library. It looked great and worked well with server-side rendering, but as of version 0.5.0, there were some issues ([#10](https://github.com/Khan/aphrodite/issues/10) and [#30](https://github.com/Khan/aphrodite/issues/30)) which prevented me from using it.\n\n#### Using CSS Modules with `cn`\n\nHere's how CSS modules are often used in React:\n\n```css\n/* header.css */\n.headerImage { ... }\n```\n\n```js\nimport styles from './header.css'\n...\n\u003cdiv className={styles.headerImage}\u003e\n```\n\nThis syntax doesn't seem to play nice with virtual CSS function `cn`, where you'd write:\n\n```js\n\u003cdiv className={cn('...')} \u003e\n```\n\nYou can use string interpolation to mix the two, but we can do better. Here's an idea: **you can make `cn` function support CSS modules.**\n\n#### New API for `cn`:\n\nHere's the new API for `cn`. Instead of just importing it:\n\n```js\n// Old way\nimport cn from '...'\n```\n\nYou'd first import `makeCn`, and then invoke it once to get `cn` back:\n\n```js\n// New way\nimport makeCn from '...'\nconst cn = makeCn(...)\n```\n\nThe argument for `makeCn` is an object, where **the values are CSS module object and the keys are \"prefixes\" for that CSS module object**.\n\nIt'll be clear when you see an example. For instance, let's say you have a CSS module like this:\n\n```css\n/* header.css */\n.headerImage { ... }\n```\n\nThen you'd write `makeCn` like this:\n\n```js\n// Import CSS module\nimport styles from './header.css'\nimport makeCn from '...'\n\n// Assign \"_\" as a prefix to use styles from header.css\nconst cn = makeCn({ _: styles })\n```\n\nThen, every class that has an underscore as a prefix will use the equivalent class (without the underscore) written on `header.css`:\n\n```js\n{/* By using _headerImage inside cn(...),\n    it applies CSS rules from .headerImage {} */}\n\u003cdiv className={cn('_headerImage -some-virtual-class some-functional-class')} /\u003e\n```\n\nYou can use multiple CSS modules too:\n\n```css\n/* header.css */\n.headerImage { ... }\n\n/* footer.css */\n.footerImage { ... }\n```\n\n```js\nimport headerStyles from './header.css'\nimport footerStyles from './footer.css'\nimport makeCn from '...'\n\n// Assign \"h_\" as a prefix for styles from header.css,\n//    and \"f_\" as a prefix for styles from footer.css\nconst cn = makeCn({\n  h_: headerStyles,\n  f_: footerStyles\n})\n\n...\n\n{/* Header Component\n    - use h_XYZ to use XYZ class from header.css */}\n\u003cdiv className={cn('h_headerImage ...')} /\u003e\n\n{/* Footer Component\n    - use f_XYZ to use XYZ class from footer.css */}\n\u003cdiv className={cn('f_headerImage ...')} /\u003e\n```\n\nSo `cn` can be used to reference virtual classes and CSS modules classes **at the same time**. Note that if you don't have any CSS modules to import, you can just call `makeCn()` without any argument.\n\nWhat's the implementation like for `makeCn`, then?\n\n#### Implementing `makeCn`\n\nAgain, here's the API we'd like to implement:\n\n```js\nconst cn = makeCn({\n  h_: headerStyles,\n  f_: footerStyles\n})\n\ncn('h_headerImage other-classes')\n\n// is equivalent to...\n\ncn(`${headerStyles['headerImage']} other-classes`)\n```\n\nFirst, write a function called `convertCssModuleClassnames`, which takes `prefixToCssmodules`, which is like:\n\n```js\n// prefixToCssmodules argument\n{\n  h_: headerStyles,\n  f_: footerStyles\n}\n```\n\nand return a function which takes an argument for `cn` (which is a string containing class names) and returns new class names.\n\n```js\nconst convertCssModuleClassnames = (prefixToCssmodules) =\u003e (classNames) =\u003e (\n  // Only proceed if prefixToCssmodules is not empty/undefined.\n  // Otherwise, just return classNames (else case)\n  prefixToCssmodules\n  ? classNames.split(' ').map((className) =\u003e { // For each class name...\n    let convertedClassname\n\n    // For each prefix (like \"h_\" or \"f_\")...\n    Object.keys(prefixToCssmodules).forEach((prefix) =\u003e {\n      // Test to see if the prefix matches the class name\n      const regexp = new RegExp(`^${prefix}`)\n      if (regexp.test(className)) {\n        // If it matches, get the CSS module object\n        // by calling prefixToCssmodules[prefix],\n        // then look up the className (without the prefix)\n        convertedClassname = prefixToCssmodules[prefix][className.replace(regexp, '')]\n      }\n    })\n\n    // If successfully converted, return both the CSS module version\n    // and the pre-conversion version (for in-browser debugging).\n    return convertedClassname ? `${convertedClassname} ${className}` : className\n  }).join(' ')\n  : classNames\n)\n```\n\nThen, you can combine it with `convertVirtualClassnames` before you export:\n\n```js\nconst makeCn = (prefixToCssmodules) =\u003e (classNames) =\u003e (\n  // First run convertVirtualClassnames, then pass the result to convertCssModuleClassnames\n  convertCssModuleClassnames(prefixToCssmodules)(convertVirtualClassnames(classNames))\n)\n\nexport default makeCn\n```\n\n#### Alternatives\n\nThere's an excellent library called [`react-css-modules`](https://github.com/gajus/react-css-modules/) which solves the same problem. I tried using it, but as of version 3.7.10, it doesn't work well inside loops and components that use `children` prop. Also, I wasn't a fan of extending React's API (adding `styleNames` attribute). Decorating every single component just for this purpose seemed overkill. I think `makeCn` is a much lighter-weight solution.\n\n#### ProTip 2 Conclusion\n\n- When functional classes don't cut it, write regular CSS using CSS modules.\n- CSS modules solve the global namespace collision problem.\n- You can rewrite `cn` to play nice with CSS modules.\n\n### :v: ProTip 3: Make `cn` more powerful by integrating the [`classnames`](https://github.com/JedWatson/classnames) package :v:\n\nThere's one more thing: Jed Watson wrote a popular library called [`classnames`](https://github.com/JedWatson/classnames), a utility for joining class names together. Here's an example:\n\n```js\n// Install using `npm install`\nimport classnames from 'classnames'\n\nclassnames('foo', 'bar'); // =\u003e 'foo bar'\nclassnames('foo', { bar: true }); // =\u003e 'foo bar'\nclassnames({ 'foo-bar': true }); // =\u003e 'foo-bar'\nclassnames({ 'foo-bar': false }); // =\u003e ''\nclassnames({ foo: true }, { bar: true }); // =\u003e 'foo bar'\nclassnames({ foo: true, bar: true }); // =\u003e 'foo bar'\nclassnames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // =\u003e 'foo bar baz quux'\n```\n\nThis is very powerful when combined with functional CSS. **If you're using `cn` to use virtual classes and CSS modules, I suggest integrating `classnames` to it**. Here's how.\n\n#### Easy Integration\n\nJust modify `makeCn` like this:\n\n```js\n// Add an underscore so it doesn't collide w/ local variable names\nimport _classnames from 'classnames'\n\n...\n\nconst makeCn = (prefixToCssmodules) =\u003e (...args) =\u003e (\n  // First run classnames, then run convertVirtualClassnames,\n  // then pass the result to convertCssModuleClassnames\n  convertCssModuleClassnames(prefixToCssmodules)(convertVirtualClassnames(_classnames(...args)))\n)\n```\n\nThen you can do:\n\n```js\nimport style from './header.css'\nimport makeCn from '...'\nconst cn = makeCn({_: style})\n\n...\n\n{/* cn now acts like Jed Watson's classnames,\n    but it now supports virtual classes (-dark-header-text)\n    and CSS module classes (_beta-header-image) */}\n\u003cdiv className={cn('bold p2', {\n  '-dark-header-text': isDark,\n  '_beta-header-image': isBeta\n})}\u003e\n```\n\nThis is powerful - you get the best of everything.\n\n---\n\n## :sunglasses: Epilogue :sunglasses:\n\nFunctional CSS is awesome, but with React, you can make it even more so. Try using virtual classes and CSS modules, encapsulated under the simple `cn` function. Your mileage may vary, but I'm enjoying the setup so far.\n\nIssues and pull requests are highly appreciated!\n\n### Author\n\n**Shu Uesugi** (Twitter: [@chibicode](http://twitter.com/chibicode) / Email: [shu@chibicode.com](mailto:shu@chibicode.com))\n\n\u003ca href=\"https://twitter.com/chibicode/status/763504990736388096\"\u003e\u003cimg width=\"480\" alt=\"\" src=\"https://cloud.githubusercontent.com/assets/992008/17598666/6b295028-5fb0-11e6-80dd-9b9432392b97.png\"\u003e\u003c/a\u003e\n\n### Appendix\n\nSome miscellaneous links I found helpful:\n\n- [How is tachyons different from inline styles?](https://github.com/tachyons-css/tachyons/issues/12)\n- [immutable-css](https://github.com/johnotander/immutable-css) by John Otander\n- [Atomic CSS Modules](https://medium.com/yplan-eng/atomic-css-modules-cb44d5993b27) by Michele Bertoli\n- [Atomic CSS](http://acss.io/) and [atomizer](https://github.com/acss-io/atomizer)\n- [Glamor - inline CSS](https://github.com/threepointone/glamor)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchibicode%2Freact-functional-css-protips","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchibicode%2Freact-functional-css-protips","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchibicode%2Freact-functional-css-protips/lists"}