How to set up Styled Components in NextJS
Tags: react, nextjs, styledcomponents, javascript
Published: 2023-03-04 08:00:24

_To read more articles like this, [visit my blog](https://www.mdfaisal.com/blog)_

## Introduction

Styled Components is a library that allows you to write CSS in your JavaScript/TypeScript code with many features like theming, nesting, and media queries. It's a great way to write CSS in React.

There are other options as well, but this is one of the best options out there because it's easy to use and has many features. It's also trendy because it's closely related to raw CSS and easy to understand.

If you are only interested in the project, you can find it on [Github](https://github.com/Mohammad-Faisal/styled-components-nextjs-integration-demo)

## Create a boilerplate project

If you already have a NextJS application up and running, you can skip this step. Otherwise, let’s create a boilerplate NextJS application first

```bash
npx create-next-app@latest
```

You can run the dev server by running the following command

```bash
npm run dev
```

Now Visit http://localhost:3000 to see your application up and running.

## Installation

First, install the dependencies:

```bash
npm install --save styled-components
npm install --save-dev @types/styled-components
```

If you are using yarn, it's highly recommended the following resolution to avoid breaking changes.

```json
"resolutions": {
  "styled-components": "^5"
}
```

It will save you from a lot of headaches.

## Setup

Next, create a `_app.tsx` file in the `pages` directory. This special file in NextJS allows you to customize the app. You can read more about it [in the documentation](https://nextjs.org/docs/advanced-features/custom-app).

```js
import { AppProps } from "next/app";
import { ThemeProvider } from "styled-components";
import React, { useState, useEffect } from "react";

const theme = {
  colors: {
    primary: "#0070f3",
  },
};

export default function MyApp({ Component, pageProps }: AppProps) {
  const [showChild, setShowChild] = useState(false);
  useEffect(() => {
    setShowChild(true);
  }, []);

  if (!showChild) {
    return null;
  }

  return (
    <ThemeProvider theme={theme}>
      <Component {...pageProps} />
    </ThemeProvider>
  );
}
```

Notice that we are using the `ThemeProvider` component from `styled-components`, and we are passing the `theme` object as a prop. This is how we can use the theme in our components.

You will also notice that we use the `useState` and `useEffect` hooks. We want to show the child component only after the theme is loaded.

Doing this is not mandatory, but it's good practice.

## Usage

Now, you can use the theme in your components. For example, you can create a `Button` component:

```js
import styled from "styled-components";

const StyledButton = styled.button`
  color: ${(props) => props.theme.colors.primary};
`;

export default StyledButton;
```

Using the `theme` prop, we can access the theme object and use its colors.

But what if we want to use the theme in a non-styled component? For example, we want to use the theme in a `div` element. We can use the `useTheme` hook:

```js
import { useTheme } from "styled-components";

const MyComponent = () => {
  const theme = useTheme();
  return <div style={{ color: theme.colors.primary }}>Hello World</div>;
};
```

Now, your components will generate the CSS class names automatically. You can read more about it in documentation

and render the button on the root page.

```js
import StyledButton from "../components/button";
import styles from "../styles/Home.module.css";

export default function Home() {
  return (
    <div className={styles.container}>
      <StyledButton> This is a button</StyledButton>
    </div>
  );
}
```

## The problem

You will notice that the tag names are not being generated. For example, if you inspect the element, you will see that the tag name is `div` instead of `sc-div`.

This is because NextJS uses server-side rendering, and the styles are generated on the server. This is not a problem in development, but it's a problem in production.

Also, the `class` name is not meaningful. Let’s fix these two problems.

## Solution

We need to use the `styled-components` babel plugin to fix this. First, install the plugin:

```bash
npm install --save-dev babel-plugin-styled-components
```

Then, add the plugin to the `.babelrc` file:

```json
{
  "presets": ["next/babel"],
  "plugins": [["styled-components", { "ssr": true, "displayName": true }]]
}
```

Notice that we have added the following configurations

```markdown
ssr: true -> This means we are enabling the server-side rendering

displayName: true -> It will set some meaningful class names
```

Alternatively, you can add the following to your `next.config.js` file:

```js
const withPlugins = require("next-compose-plugins");
const withTM = require("next-transpile-modules")(["styled-components"]);

module.exports = withPlugins([withTM], {
  webpack(config, options) {
    return config;
  },
});
```

Now restart the server, and you will see that the button className will be `button__StyledButton-sc-egbi27-0 exllgz`

This makes it easier to understand.

## Handle server-side styles

The next step is to handle the server-side styles. We need to add the `ServerStyleSheet` from `styled-components` to the `_document.tsx` file:

```js
import Document, { Html, Head, Main, NextScript } from "next/document";
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }

  render() {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}
```

Here we are using the `ServerStyleSheet` to collect the styles from the server, and then we are adding them to the `styles` prop.

## Conclusion

This was a straightforward example, but you can use the `styled-components` library to create complex components with many features.

To learn more about the library, you can read the documentation

## GitHub Repo:

```
https://github.com/Mohammad-Faisal/styled-components-nextjs-integration-demo

```