Styled Components in React: Moving away from SCSS

CSS Specificity Wars

As we continue to migrate our monolithic system into a microservices-based architecture and navigate through the micro frontend landscape here at FloQast, it has become increasingly difficult for me to manage all the CSS that style our React components. While I love that micro frontends allow us to isolate team code and support independent deployments, I’ve realized that they also magnify the traditionally global nature of the stylesheet language.

For example, if I’m on micro frontend team A and added the following CSS, I’d probably be pretty disappointed with the styling of my component.

// micro frontend team A
.icon {
    color: blue;
}

// micro frontend team B
.icon {
    color: white;
 }

Clashes can occur when different micro frontends unintentionally grab the same selector or class name. Because our teams sometimes work on the same page at the same time, ensuring that each team is independently writing their styles can be challenging. This is especially true when the code is split amongst various repositories and different teams may be updating CSS at different times.

I take extra care to make sure new CSS rulings don’t mistakenly affect other components in the app. While CSS offers a level of reusability that enables me to avoid redundant style declarations, this aspect can also create dependencies between HTML elements and CSS rulings, typically through the following ways:

1. Multiple selectors are grouped to target and style different HTML elements.

.percentage-number, .percentage-sign { 
  font-size: 40px; 
  line-height: 1; 
}

2. Multiple class names are applied to the same HTML elements, causing them to be targeted by multiple CSS rules.

.success { color: green; } 
.status-icon { font-size: 48px; } 

<div className="success status-icon" />

I find it hard to keep track of these dependencies over time, particularly when there are other developers touching the code. I may forget which rules actually need to be updated or deleted.

So, is there another way of organizing stylesheets?

Decoupling Monolithic Stylesheets

To better manage our CSS, we recently implemented styled-components, a CSS-In-JS library that allows us to modify CSS without unexpected side effects, providing us with confidence that our micro frontends will behave as expected when stitched together.

Styled Components bring your styles to the age of components. If you’ve worked with React before, you might know that it is best practice to create components that are completely independent of each other and to use single class names for styling. Styled Components help you enforce these best practices by encouraging a one-to-one relationship between an HTML element and its CSS through unique class names for your styles. They also bridge the gap between components and styling by giving you the ability to style components in a reusable manner.

Styled Components allow you to not worry about managing stylesheets and to leverage the Javascript ecosystem by letting you write your CSS directly in your Javascript files.

Using Styled Components

Styled Components use the power of tagged templates to style components.

“It removes the mapping between components and styles. This means that when you’re defining your styles, you’re actually creating a normal React component, that has your styles attached to it.”  -Styled Components

Let’s take a peek at the magic:

import styled from 'styled-components';

// Styled Component named StyledLabel
const StyledLabel = styled.label`
    color: gray;
    font-weight: 700;
    font-size: 12px;
    text-transform: uppercase;
`;

const Component = () => {
  // Use it like any other component
  return <StyledLabel>Search</StyledLabel>;
}

In this example, StyledLabel is a Styled Component that will render an HTML label with the styles attached to it. The styled method will then convert the styling from Javascript into actual CSS.

Here is what the original component and CSS looked like:

label { 
  color: gray; 
  font-weight: 700; 
  font-size: 12px; 
  text-transform: uppercase; 
} 

<label>Search</label>

When Styled Components create the StyledLabel, it will use a hashing algorithm to generate a unique identifier. This is what prevents class names from overlapping, saving you the trouble of coming up with your own.

<label class="jewpRe bkIsBc">Search</label>

You can also transform your own custom components. Just be sure to pass in a className prop to the underlying DOM element.

const SearchBar = ({ className, value, onChange, placeholder}) => {
    return {
        <TextInput
            className={className}
            value={value}
            onChange={e => onChange(e.target.value)}
            placeholder={placeholder}
        />
    };
};

const StyledSearchBar = styled(SearchBar)`
    line-height: 18px;
    font-size: 18px;
    margin: 1px -5px;
`;

Now, when you add or change your CSS, you don’t need to worry about your styles leaking unpredictably into other parts of the app. Similarly, when you delete a component, you also delete all the styles along with it, eliminating dead code and the need to hunt for class names.

Other Benefits

Besides scoping styles and improving the developer experience, Styled Components also bring the following:

  • Automatic Critical CSS: Inject only the critical CSS tied to rendered components, preventing unnecessary loading of code.
  • Automatic Vendor Prefixes: Apply vendor prefixes to CSS rulings, so you don’t have to.
  • Dynamic Styling: Pass down props the same way you would to regular React components.
  • Themes: Easily define common styling. React’s Context API’s provides the ability to pass props to all styled components within the ThemeProvider wrapper.

Drawbacks

In regards to performance, Styled Components do make your .js bundles slightly heavier and will add an extra layer to your application. However, as a tradeoff, the library helps you reduce the number of network requests for .css files since only the styles necessary for a page are loaded.

Conclusion

CSS-In-JS libraries will likely gain further traction in modern frontend development. Especially with the popularity of component-based libraries/frameworks like React. If your team is currently leveraging reusable components, CSS-In-JS libraries may be worth looking into. They can help you sidestep some common CSS frustrations.

Additional Resources

Stephanie Chiu

Software Engineer at FloQast. Hobbies include binge-watching TV shows and traveling to (and eating through) new cities.



Back to Blog