Developers October 7, 2020

How do you style your React components?

Steven Kim @stevenkkim

Hi Everyone,

So far I've been using a few different styling methods for my app. My current approach has been:

  • First use Bootstrap components (customized with scss)
  • Second, customize with Bootstrap utility classes
  • Third, inline styling for things that that utility classes can't handle

It's worked pretty well so far, but definitely running into issues with inline css like not being able to do :hover states. I'm considering adopting a CSS-in-JS library but as I did some research, there are so many ways to style, including:

  • Import CSS
  • Import Sass/Scss
  • Inline CSS
  • CSS Modules
  • CSS Modules w/ Sass/Scss
  • Utility-first frameworks like Tailwind
  • CSS in JS
    • styled-components
    • emotion
    • jss
    • aphrodite
    • radium
  • Probably more options that I'm missing

So I'm curious – what do you use and why?

  1. 5

    My preference is CSS Modules with SCSS. Very maintainable. Good separation of concerns. Keeps naming simple.

    1. 2

      +1 for CSS modules. It removes an entire class of CSS headaches, and automates the important parts of the BEM convention IMHO.

      I used to do that with SCSS, but a coworker convinced me that you don't really need SCSS for much most of the time, and it adds complexity. Worse, it encourages you to nest selectors, which looks nice in dev but adds a lot of bytes of bloat.

      The killer feature of SCSS for me was variables, but CSS variables are here now and they work at runtime, so I struggle to think of a must-have use SCSS now for most sites.

      1. 1

        These days I basically only use it for Mixins, which I find extremely helpful for DRYness in CSS modules. I actually use CSS variables instead of Sass variables. I do very little nesting, but I love it for media queries.

        All that being said, I agree that it's not a necessity at all.

        1. 1

          Yes I forgot mixins. I guess that's the another killer feature.

    2. 1

      Thanks Griffin. Do you keep your component file in a folder with the css modules file? Along with other related files (e.g. tests)?

      1. 1

        I used to do that, these days I actually prefer to dump that all into a single /components folder. Removes some overhead from dealing with the extra level of depth, and i find it just as scannable.

        1. 1

          Yeah, I do that too (everything in a components folder). Just wondering since adding CSS modules would obviously increase the number of files in that folder.

          1. 2

            I have projects with 100+ components in them organized that way. I haven't had an issue with it. Honestly, I'm usually not browsing through the file tree anyway. ⌘ + P is your friend (in VSCode at least)

            1. 2

              Thanks for your perspective! I'm at around 60 components in the folder but was starting to get worried about finding things and maintainability. But I think you're right that ⌘ + P mostly solves that problem.

  2. 3

    Tailwind CSS + CSS modules + BEM
    It is framework agnostic, highly customizable, performant (no CSS-in-JS) AND maintainable.

    1. 2

      Thanks for your perspective! I am a bit worried about css-in-js performance.

      1. 1

        And you should be, for sure.
        If you want CSS-in-JS, then check Styled Components + Styled System. Used both for about 1y~ before switching to CSS modules + Tailwind - which is my recommendation.
        You can use only Tailwind btw, no need for CSS modules (only used because I like to keep my stuff organized).

        1. 2

          Thanks. Do you use CSS modules for styling that Tailwind does not have a utility class for? For example, if you wanted a very specific style like margin: 1.125rem; or border: 0.5px;

          And how do you handle styling with js variables? Currently I'm doing something like style={{ width: widthVariable }}

          1. 1

            Nope, I use CSS modules to compose classes with Tailwind, then I set the classes I created on my components.
            Actually, Tailwind has so many utility classes that I don't think you will need to create specific styles, really - but you can if you want.

            Here, take a look: https://gist.github.com/infelipe13/00a40fcef45945b5ef192b97a922c556

            This is how I've been using both together. Without CSS modules, the className prop would be quite bloated with utility classes. Reason is I like to keep my template (returned element) as clean as possible. But worry not because like I said before, it is ok to use Tailwind alone and I already saw lots of people doing it :)

            About styling with JS variables, well... I don't. It doesn't support pseudo-elements like ::after and ::before, nor states like :hover. Also, you can easily customize Tailwind and use a class instead of a style (which always seemed kinda hacky to me).

            I enjoy creating my own stuff. Had a lot of trouble in the past trying to style components made by someone else or integrating them with something. That is why I avoid Material UI, Bootstrap and stuff. The time I would waste trying to apply validation or customizing Material UI could be spent making my own components that I know how they work internally and how to integrate them with libraries.

            1. 2

              Thanks for sharing. With Bootstrap, I prefer putting classes directly into the components, but with Tailwind's large number of classes I could see how that might get messy, and putting your Tailwind styles in CSS modules is a neat approach.

              1. 1

                You're most welcome, Steven. If you have any questions, feel free to ask :)

  3. 3

    Hi @stevenkkim, interesting question, and I am curious what others will share with us.

    I used SCSS with Bootstrap a lot in the past. But then I tried CSS-in-JS and liked the approach and idea behind it. I use styled-components and my current projects at work. I think it's maintainable, and you get isolated and scoped CSS. Additionally, you have access to JS variables, which lets you adjust CSS based on specific states quickly.

    As of today, Tailwind is my new must-have when bootstrapping apps. The utility-first idea is excellent and reduces lots of clutter, utility classes, and duplication of CSS (which happens fast in CSS), IMHO.

    I have not got my hands on CSS-Modules, but I have heard great things about it.

    1. 1

      I have my doubts about Tailwind maintainability and caching for most purposes. But with something like React where you componentize everything I can see it shine.

      1. 1

        This is the first time I've heard anyone voice concerns about maintainability and/or caching with Tailwind. Could you elaborate why? I'm curious.

        1. 1

          Take for example a bootstrap button, that will have following classes:
          "btn btn-primary"

          A Tailwind button could have following classes:
          "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"

          Now if you decide you want all your buttons to not have rounded corners anymore you better hope you componentized the button because otherwise you will have to look for every button in your code and remove the class. With something like Bootstrap (or any BEM inspired CSS system) you can just overwrite the CSS of ".btn" in 1 place to remove the rounded corners.

          1. 2

            I think Tailwind’s approach to this problem is this:
            https://tailwindcss.com/docs/extracting-components

            1. 1

              Yeah, I recently read about this. But I almost never see anyone doing it.

              I really need to give it a chance, I really like how Steve Schoger designs stuff.

            2. 1

              Exactly, I think that especially this part explains it pretty good: https://tailwindcss.com/docs/extracting-components#extracting-css-components-with-apply. You could create your own bootstrap-like classes with @ apply.

        2. 1

          I just wanted to ask the same question. Especially the caching part is of interest to me.

          1. 2

            We’re debating tailwind at my current company. Our main concern is you’re basically leaking out implementation details out into your markup. Instead of having an element’s UI be encapsulated away with a class called avatar-card you have something that looks like “class=bg-light radius-3px box-shadow-medium etc”. You have to be very diligent about this especially if you have a large system. Markup would also be harder to read.
            You could always just use the utility classes to compose classes.

            1. 1

              Hi @robb,

              I had the same concerns in the beginning too: that the HTML gets too complicated to read, maintaining components or design changes become very hard, and so on. But they did a pretty good job taking these concerns away from me.

              You gotta read https://tailwindcss.com/docs/extracting-components, to find out more about it. I think you did already when you mentioned composing classes.

              I think when you follow that path, you can do great things with Tailwind. I've seen many examples in my network already.

    2. 1

      Hi Stefan, thanks for your feedback. I think you make a really good point on using js variables to adjust css. I do that every once in a while and I think it's something that css-in-jss offers that other solutions lack.

      I may switch from Bootstrap to Tailwind sometime in the future, but right now it's working great for me so I don't have a lot of motivation to refactor my project mid-stream. I think at some point if I get frustrated with Bootstrap, Tailwind will be first on the list to try.

      Do you know why styled-components seems so much more popular than emotion? The two seem very similar in functionality but I think I like emotion's ability to do inline css-in-js which styled-components doesn't seem to have.

      Have you run into any performance issues with styled-components? That seems to be my main concern with css-in-js.

      1. 1

        Hi Steven,

        Yeah, don't rush into Tailwind and refactor projects just so you can use Tailwind. You can create your own Tailwind-like utility classes also with Bootstrap and SASS @mixin for instance.

        Not sure what's the key difference that got SC where it is now compared to other CSS-in-JS solutions (https://www.npmtrends.com/styled-components-vs-emotion-vs-aphrodite). Maybe it's because of the tooling around SC. There are lots of packages enhancing the experience (e.g. https://github.com/styled-system/styled-system, https://github.com/styled-components/styled-theming), but that's also true for emotion, I think.

        I have not yet done some performance tests, but I always wanted to measure the impact it has on SSR and hydration. Because in the end, you write more JS code, which means computing power is required when hydrating SSR output (but also in general). I have not validated that with numbers. Have you?

        1. 1

          I have not seen any numbers, so I'm not sure. For the time being, I'm going to rely on Bootstrap whenever possible and keep my css-in-js in limited cases where I need it

  4. 2

    I use CSS Modules & Variables & SCSS (with Next.js as the framework). Also I wrote a small helper function that makes it a little easier to use CSS Modules styles from within React https://gist.github.com/andyfischer/a5059679e450562e42560ce25352d8cb

    I tried CSS-in-JS for a while but decided I'm not a fan. The things I don't like:

    1. I don't think it's very future proof, in a few years I think most teams are going to regret all the overcomplicated styled-components / emotion based code that they have.

    2. Writing CSS/SCSS in its own seperate file is just easier IMO. For dynamic values, using CSS Variables is easier than writing that "${props => props.etc}" stuff.

    3. Vastly easier to debug this code using Devtools. With CSS-in-JS the default debugging experience is that you have a ton of anonymous styles and you're not sure where they came from.

    4. Having good page load optimization is more tricky with CSS-in-JS. If you do it wrong (like if the DOM is initially rendered before the CSS-in-JS based styles are mounted) then you get an extremely ugly pop-in effect. There's some new platforms like atlassian-labs/compiled that probably do a good job here. But I'd rather just use CSS Modules which has predictable performance, I can count on it to work great without needing a space-age build system.

    1. 1

      Thanks for your feedback. Lots of interesting things to think about here!

  5. 2

    I decided a long time ago that I have to focus on core app functionality and can't afford to spend too much time on the styling game. So, I went with Semantic UI, using their styling for my React components (written in ClojureScript). I wrote perhaps 50 lines of CSS overrides over the last 5 years.

    So far it's worked out very well for me, although I am at a point where I could really benefit from custom CSS for mobile screens and for complex tables.

    1. 1

      Thanks for sharing. I use a very similar approach with Bootstrap for baseline components and styles. I'm much more focused on building the app rather than styling it.

  6. 1

    I think one important qusestion to take in to consideration when choosing a css method and framework is, maybe obvious but sometimes overlooked, what type of product or website are we building? UI libs are gonna have their strenghts and their weaknesses depending on end product. For example some will be good for building out a dashboard type app but wont be optimal when it come creating a landingpage, blog, forum etc.

    The last framework that I have worked with that I really like is Chakra UI. Very quick for building a Saas type app

    1. 1

      Interesting, I hadn't heard of Chakra UI. thanks for sharing!

  7. 1

    I prefer to use Emotion and the css prop so that I can drive styles from within JS scope.

    It's plain and simple. No extra files. Just plain CSS.

    Tailwind is amazing but using JS to conditionally change styles is clunky and I don't want to burden others with the need to learn all the utility classes before they can be productive.

    1. 1

      Thanks for sharing! Emotion seems better than style-components to me, but the latter seems far more popular – not sure why.

  8. 1

    Styled components when I have my own design system. It can be used with the likes of minimal visual primitives like Rebass.

    When I want to bootstrap something quickly, I might skip all of it and use an existing design system like Bootstrap, Evergreen or Material UI

  9. 1

    depending on project but using mostly:

    • material-ui jss version - when you want your app to have material design look
    • styled-components - if you organize code well, code looks tidy and separated enough, no need for classes lib (no cx and conditions needed, just do it in the component)
    • sass - leveraging BEM on this one, using for smaller projects

    I plan to try tailwind next and to make my own customizable component library in the near future.

    I steered away from foundation, bootstrap and the likes 4 years ago as it bloated my code back then, never went back so I don't have experience with bootstrap components

  10. 1

    Hi, it depends on project.
    In my chat components library https://github.com/chatscope/chat-ui-kit-react i use scss and BEM in separated npm package for theming. It allows me to make new themes in dedicated package.
    But it's library..... In applications i use css modules + scss + bootstrap, MUI, emotion, SemanticUI etc. depending on current app. For simple one-shot app with no prospects for future development SemanticUI is ok, but for long-lived apps i prefer good old scss.

    1. 1

      Amazing how many UI kits are out there. Thanks for sharing!

  11. 1

    I use JSS! No reason why, it was the first tutorial I read

    1. 1

      👍 If it works for you, that's what's important, right?

  12. 1

    I use Material UI and a lot of the basic styling is done with a MUI theme. Next I use styled components, and then composition. Lastly I use inline styles, but that usually ends up mostly just being for one-off positioning tweaks. I have on occasion used the makeStyles hook as well.

    1. 1

      Seems like a sensible approach. Thanks for sharing!

  13. 1

    I just use good ole SASS!

  14. 1

    I use scss. Why: Separation of concern, portability with other frameworks, smaller learning curve

  15. 1

    I currently only use React with MaterialUI, so I use their recommended styling option: https://material-ui.com/styles/basics/#hook-api

  16. 1

    I've tried a bunch and my go-to is Styled Components. It feels like natural CSS writing without the class bloat in your React components.

    1. 1

      Thanks Ryan. Did you ever consider Emotion? It appears to have all the benefits of Styled Components but also lets you write "inline" styles attached directly to className without a predefined component. But it seems like Styled Components is significantly more popular, and I'm trying to figure out why.

  17. 1

    I use SCSS. Great extension of CSS and makes it more readable with nesting and separating media queries. Although i have been thinking about switching over to styled components

    1. 1

      👍 Yeah, once you start using scss it's hard to go back to plain old css.

Recommended Posts