Server side rendering Styled-Components with NextJS
Tags: javascript, ssr, nextjs, react
Published: 2020-06-10 15:31:49

_This post was originally published in my [Medium](https://medium.com/@koalamango) blog._

<hr />

I switched to styled-components for most of my projects nearly a year now but never used it with Next.js until recently. This might be a bit late to the party but I feel it's definitely worth sharing the neat trick of **ServerStyleSheets**.

🔖 **TL;DR:** You can find my example [repo](https://github.com/koalamango/nextjs-style-components-starter) here 😊


### How does it work?

- **[Styled-Components](https://styled-components.com/docs/advanced#server-side-rendering)**

Styled-components supports concurrent SSR (server side rendering) with stylesheet rehydration. The basic idea is that when your app renders on the server, you can create a **ServerStyleSheet** and add a provider to your React tree which accepts styles via a context API. This doesn't interfere with global styles, such as keyframes or createGlobalStyle and allows you to use styled-components with React DOM's various SSR APIs.

- **[NextJS](https://github.com/vercel/next.js/blob/master/examples/with-styled-components/pages/_document.js)**

In Next.js, `<Document />` wraps the `<html>`, `<body>`, `<head>` tags and runs them through a renderPage method which synchronously renders on the server side. We can override the default<Document/> by adding a `_document.js` file in `pages` folder to inject the server side rendered styles into the `<head>`.

That's pretty neat, huh!

### Getting Started

Make sure you have these packages in `package.json`:

```js
{
"dependencies": {
  "next": "latest",
  "react": "^16.8.0",
  "react-dom": "^16.8.0",
  "styled-components": "latest"
},
"devDependencies": {
  "babel-plugin-styled-components": "latest",
}
```

And in `.babelrc`

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

Now, feel free to add your styles to `./pages/index.js`. For example, let's add simple GlobalStyle for the heading and Styled.div for the container:

```js
import Head from 'next/head';
import styled, { createGlobalStyle } from 'styled-components';
const GlobalStyle = createGlobalStyle`
 h1 {
   font-size: 4rem;
 }
`;
const Container = styled.div`
  text-align: center;
`;
export default function Home() {
  return (
    <>
      <Head>
        <title>SSR styled-components with Next.js Starter</title>
      </Head>
      <Container>
        <GlobalStyle />
        <h1>Hello, world!</h1>
      </Container>
    </>
  );
}
```

Finally, let's take a look at `_document.js`: _this is where the magic happens_.

Styled-components creates an instance of `ServerStyleSheet` This stylesheet retrieves any styles found in all the components inside our `<App />`. This then gets passed into our `Html` template later on.

```js
import Document 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();
    }
  }
}
```

- `sheets.collectStyles` collects all of the styles from the app's components.
- `sheets.getElement()` generates the style tag and you need to return it as props called `styles`.

### Testing the app

To view it locally, run `npm run dev` then visit `http://localhost:3000`

If you disable JavaScript on the browser (e.g in Chrome: Settings / Site settings / JavaScript / Blocked), you should still be able to see the styling applied to headings and container, even though the JavaScript didn't run locally (see the screenshot below).

![Hello world](https://dev-to-uploads.s3.amazonaws.com/i/jxf3iigld87ixio8ccwk.png)


### That's it!

This is a quick walkthrough to explain how to render server-side styled-components works with Next.js. The steps are pretty straight forward and easy to build on once you have the basics in place.

I remember in the past pulling my hair out to get styles working the way I wanted on the server side. Next.js and the support of styled-components are proving a really powerful tool to make this much simpler to achieve.

Hopefully this tutorial helps to ease some headaches for you! 😃