DEV Community

Cover image for Moving from SCSS to styled-components: Advantages and caveats
Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

Moving from SCSS to styled-components: Advantages and caveats

Written by Eslam Hefnawy✏️

Frontend frameworks like React have changed the way we interpret the separation of concerns. According to the vanilla approach, HTML, CSS, and JavaScript were all considered separate concerns. Your application’s markup, styles, and behavior were all separated and maintained in different files.

React, on the other hand, breaks down the application into components that have both rendering logic and UI logic. These independent, reusable pieces are coded in isolation but assembled later into compositions of components, templates, and pages.

React components and their smaller building blocks, called elements, take care of everything that you might expect from a part of your UI, including event handling, state changes, and displaying data. They do this by mixing JS with HTML into JSX, a syntax extension of JavaScript.

This mixture of markup and behavior is widely adopted now in the frontend world, and React is one of the most popular frameworks. But when it comes to styling, opinions are split: while some prefer styled-components, others can’t let go of Sass/SCSS.

In this guide, we’ll explore both options and evaluate the advantages and disadvantages of moving from SCSS to styled-components in your React application.

For a visual representation, we’ll create an author box in React and style it in both ways. You can find the code here:

Our finished product will look like this:

Styled Author Box React App Finished Product

Let’s dive in!

LogRocket Free Trial Banner

Prerequisites

In this tutorial, we’ll use React to create components. While you don’t have to be familiar with styled-components or Sass, you should ideally have some hands-on experience with JavaScript and CSS.

Creating an author box in React with no styling

Let’s walk through how to build an author box with no styling in React.

Step 1: Install React and dependencies

We’re just using a sandbox for the purpose of this tutorial, but if you’re creating a real application, you’ll need to install React, ReactDOM, styled-components, and Sass. Your project folder should include the following files.

Author Box React App Project Folder

Now let’s start populating the index.js file. First, import React and styled-components, respectively, into the styles.scss file.

import React from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
import "./styles.scss";
Enter fullscreen mode Exit fullscreen mode

I’ve commented out both libraries for now so that we can focus first on the markup of the component. Your index.js you should look like this:

import React from "react";
import ReactDOM from "react-dom";
// import styled from "styled-components";
// import "./styles.scss";

import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

Your index.html file should include the following code.

<html>

<head>
  <title>React Exercise</title>
  <meta charset="UTF-8" />
</head>

<body>
  <div id="app"></div>

  <script src="../src/index.js"></script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

However, if you’re using the fiddle above, the index.html document will look slightly different, so be aware of this when playing with the code.

Now we’re ready to create the <AuthorBox> component. Remember that in React, all components start with a capital.

Step 2: Build the elements of the author box with JSX

Our component will consist of the following elements.

  • An author name (<H3>)
  • An author bio: (<p>)
  • A social URL (<a href>)
  • An author avatar (<img>)
  • A wrapper to hold all these (<div>)

In the App.jsfile, add the following code.

import React from "react";
// import "./styles.scss";

const AuthorBox = () => (
 <div>
   <img src="" alt="" />
   <h3>Author name</h3>
   <p>Author bio</p>
   <a href="#socialURL">Social URL</a>
 </div>
);

export default function App() {
 return <AuthorBox />;
}
Enter fullscreen mode Exit fullscreen mode

We’re importing React from react so that we can use JSX syntax. We’re defining the AuthorBox component as a simple ES6 arrow function, which takes no parameter for now and outputs plain HTML markup. In the end, we’re exporting this component as the default export for the App.js file.

You should see this rendered:

Author Box Elements

Before we move on to styling, let’s add an image. For the image to be displayed in the sandbox, we must first add it to the public folder.

Add Image to Public Folder

Your code should now look like this:

import React from "react";
// import "./styles.scss";

const AuthorBox = () => (
 <div>
   <img src="cat" alt="" width="200" />
   <h3>Author name</h3>
   <p>Author bio</p>
   <a href="#socialURL">Social URL</a>
 </div>
);

export default function App() {
 return <AuthorBox />;
}
Enter fullscreen mode Exit fullscreen mode

And it should render this:

Author Box Elements With Image

Now we can start styling. We’ll add SCSS styles, then refactor the code to styled-components.

Step 3: Style the author box with SCSS

First, add the styles to the styles.scss file.

$size-s: 14px;
$size-m: 16px;
$size-l: 20px;
$size-xl: 24px;

.wrapper {
  display: flex;
  flex-flow: column nowrap;
  justify-content: flex-start;
  align-items: flex-start;
  align-content: center;
  padding: 10px;

  &-border {
    border: solid 1px grey;
  }
}

.author {
  &-name {
    font-size: $size-l;
  }

  &-bio {
    font-size: $size-s;
  }

  &-socialUrl {
    text-decoration: none;
    font-size: $size-m;
  }

}
Enter fullscreen mode Exit fullscreen mode

The next step is to add these styles to the elements. Go ahead and update the AuthorBox component. I’ve added some lorem ipsum text to the author bio for demonstration purposes.

import React from "react";
import "./styles.scss";

const AuthorBox = () => (
 <div className="wrapper wrapper-border">
   <img src="cat" alt="" width="200" />
   <h3 className="author-name">Author name</h3>
   <p className="author-bio">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget consectetur augue. Cras non fermentum massa. Duis at nulla ac nibh venenatis interdum. Pellentesque in rhoncus mi. Suspendisse tempor efficitur massa, sit amet dignissim sapien ultricies vel.
</p>
   <a className="author-socialUrl" href="#socialURL">
     Social URL
   </a>
 </div>
);

export default function App() {
 return <AuthorBox />;
}
Enter fullscreen mode Exit fullscreen mode

Your component should now render like this:

Author Box Styled With SCSS

What if we want to assign different color schemes to the author boxes? Let’s say we want a pink box and a blue box with adjusted font colors. We’ll need to create additional classes.

.background {
 &-pink {
   background-color: pink;

   h3,a {
       color: palevioletred;
   }
 }
  &-blue {
   background-color: skyblue;

   h3,a {
     color: blue;
   }
 }
Enter fullscreen mode Exit fullscreen mode

Let’s duplicate the author box in the app output so that we can see both styles in parallel. To do this, adjust the default export code in the App.js file.

export default function App() {
 return (
   <>
     <AuthorBox />
     <AuthorBox />
   </>in
 );
}
Enter fullscreen mode Exit fullscreen mode

Notice that now the AuthorBox components are wrapped in an empty tag, which is a React Fragment.

To add the background colors, we’ll need to pass the AuthorBox component a background property. We’ll condition the background to be pink when the AuthorBox has the isPink property and to be blue otherwise.

 const background = `${isPink? "backgroundPink" : "backgroundBlue"}`;
Enter fullscreen mode Exit fullscreen mode

We updated the AuthorBox at the bottom so that one of the components is pink.

import React from "react";
import "./styles.scss";
// import classNames from "classnames";

const AuthorBox = ({ isPink }) => {

 const background = `${isPink? "backgroundPink" : "backgroundBlue"}`;

 return (
   <div
     className={`wrapper wrapperBorder ${background}`}
   >
     <img src="cat" alt="" width="200" />
     <h3 className="authorName">Author name</h3>
     <p className="authorBio">
       Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget consectetur augue. Cras non fermentum massa. Duis at nulla ac nibh venenatis interdum. Pellentesque in rhoncus mi. Suspendisse tempor efficitur massa, sit amet dignissim sapien ultricies vel.
     </p>
     <a className="authorSocialUrl" href="#socialURL">
       Social URL
     </a>
   </div>
 );
}

export default function App() {
 return (
   <>
     <AuthorBox isPink />
     <AuthorBox />
   </>
 )
}
Enter fullscreen mode Exit fullscreen mode

If we want to add one more class to the wrapper for a top margin, for example, the code becomes quite crowded.

<div className={`wrapper wrapperBorder ${background} wrapper-margin`}>
Enter fullscreen mode Exit fullscreen mode

Finally, let’s make the author image round. We need to add another class since we want it to be an option, not mandatory. Create a class called avatar and add it to the <img> tag.

.avatar{
   border-radius: 50%;
 }
Enter fullscreen mode Exit fullscreen mode

We want this class to apply only to one of the containers — let’s say, the blue one. We need to condition this.

const AuthorBox = ({ isPink }) => {

 const background = `${isPink? "backgroundPink" : "backgroundBlue"}`;
 const avatar = `${isPink? " " : "avatar"}`;

 return (
   <div
     className={`wrapper wrapperBorder ${background}`}
   >
     <img className={`${avatar}`} src="cat" alt="" width="200" />
     <h3 className="authorName">Author name</h3>
     <p className="authorBio">
       Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget consectetur augue. Cras non fermentum massa. Duis at nulla ac nibh venenatis interdum. Pellentesque in rhoncus mi. Suspendisse tempor efficitur massa, sit amet dignissim sapien ultricies vel.
     </p>
     <a className="authorSocialUrl" href="#socialURL">
       Social URL
     </a>
   </div>
 );
}
Enter fullscreen mode Exit fullscreen mode

Below are our final components.

Author Box App Final

While this is definitely achievable for such small projects, as the code base grows, it becomes increasingly troublesome to maintain the styles. Let’s see what the same components would look like with styled-components.

Step 4: Style the author box with styled-components

I’ve copied the code from the index.js and app.js files, but this time our styles will stay inside a style.js file.

styled-components Folder

How can we refactor from SCSS to styled-components? First, we’ll adjust the styles, and our code should look like this:

import styled from "styled-components";

const sizeS = '14px';
const sizeM = '16px';
const sizeL = '20px';

export const Wrapper = styled.div`
 display: flex;
 flex-flow: column nowrap;
 justify-content: flex-start;
 align-items: flex-start;
 align-content: center;
 padding: ${sizeS};
 border: solid 1px grey;
 background-color: ${props => (props.isPink ? "rgb(252, 230, 234)" : "rgb(199, 233, 247)")};
`

export const Avatar = styled.img`
 border-radius: ${props => (props.isRound ? `50%` : ` `)};
`

export const Name = styled.h3`
 font-size: ${sizeL};
 color: ${props => (props.isPink ? "rgb(150, 13, 58)" : "rgb(4, 46, 94)")};
`

export const Bio = styled.p`
 font-size: ${sizeM};
`

export const SocialURL = styled.a`
 text-decoration: none;
 font-size: ${sizeS};
 color: ${props => (props.isPink ? "rgb(150, 13, 58)" : "rgb(4, 46, 94)")};
`
Enter fullscreen mode Exit fullscreen mode

This is 34 lines of code, compared to 54 in the SCSS version.

Next, adjust the App.js file.

import React from "react";
import { Wrapper, Avatar, Name, Bio, SocialURL } from "./styles";

const AuthorBox = ({ isPink, isRound }) => {
 return (
   <Wrapper isPink={isPink}>
     <Avatar isRound={isRound} src="cat" alt="" width="200" />
     <Name isPink={isPink}>Author name</Name>
     <Bio>
       Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed eget consectetur augue. Cras non fermentum massa. Duis at nulla ac nibh venenatis interdum. Pellentesque in rhoncus mi. Suspendisse tempor efficitur massa, sit amet dignissim sapien ultricies vel.
     </Bio>
     <SocialURL isPink={isPink} href="#socialURL">
       Social URL
     </SocialURL>
   </Wrapper>
 );
};

export default function App() {
 return (
   <>
     <AuthorBox isPink isRound/>
     <AuthorBox />
   </>
 );
}
Enter fullscreen mode Exit fullscreen mode

Now we have 29 lines of code instead of the 36 lines from the SCSS version.

The components should render like this:

Author Boxed With styled-components

The styled-components can be even cleaner if you use switch functions, but with this setup, you can see how easy it is to mix and match the components and properties. If you want the avatar to be round in the blue version, just pass the isRound property to the second component.

export default function App() {
 return (
   <>
     <AuthorBox isPink />
     <AuthorBox isRound />
   </>
 );
}
Enter fullscreen mode Exit fullscreen mode

Author Box Final Components

SCSS vs. styled-components

styled-components enable you to fully separate UI from the function and state of components. But are they really better than Sass/SCSS? Let’s compare the advantages and drawbacks of both libraries.

Overwriting styles and naming conventions

Since styled-components don’t come with any globally scoped selectors, you don’t need to worry about conflicts and styles overwriting each other. Although Sass comes with nice upgrades such as nesting and variables, it’s more likely to lead to overwriting styles.

styled-components offer simplicity in naming. With Sass/SCSS — whether combined with BEM or not — there’s a lot of going back and forth to find the correct classes. You can imagine what a challenge it would be to determine what overwrites what in a large project.

Also, in the case of Sass stylesheets, the code quickly becomes crowded when you start adding classes, especially if you want the additional styling to be optional for the user.

Customization and reuse

styled-components are easier to reuse than those styled with Sass. If you want to share a component between two higher-order components or even between two apps, you can be sure that the logic and styling will remain consistent.

They’re also easy to customize by simply passing additional props. The ability to condition properties such as sizes and colors to props makes the styles more dynamic and easier to handle in big projects.

Performance and caching

styled-components are rendered only if the component is on screen, while Sass is processed anyway in most cases, although this can be controlled.

This is a point for styled-components, but the drawback in this case is that once the styles are parsed, all the code is added into the index.html file and there’s no way to separate the CSS from the rest.

Another disadvantage of styled-components is that the class names are generated dynamically, which can cause issues with caching between builds or renders. With Sass, this issue doesn’t exist.

Debugging

The method of scoping styled-components is superior in terms of reusability and customization, but because the components are more generic, it can be harder to debug them.

Moreover, due to all the conditioning and logic mixed with styles, they’re also harder to read. With Sass/SCSS, the output is plain CSS and debugging is easier.

Learning curve and legacy code

The learning curve for styled-components is steeper than that of Sass/SCSS, and not all developers like to mix their CSS with JS. But with styled-components, you can still use plain CSS. You don’t have the flexibility to do things both ways with Sass.

Finally, Sass is more likely to be found in legacy projects. Integrating both libraries into a single application can be confusing. Although styled-components offer myriad advantages, some developers prefer the stability and more universal character of Sass over the novelty of styled-components.


Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.

Alt Text

LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — Start monitoring for free.


The post Moving from SCSS to styled-components: Advantages and caveats appeared first on LogRocket Blog.

Top comments (1)

Collapse
 
yonasayfu profile image
yonasayfu

It is helpful content and the example is very descriptive.Thank you. I