loading...
Cover image for Server side rendering Styled-Components with NextJS

Server side rendering Styled-Components with NextJS

koalamango profile image Jessie W. ・3 min read

This post was originally published in my Medium blog.


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 here 😊

How does it work?

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.

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 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:

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

And in .babelrc

{
  "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:

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.

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

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! 😃

Discussion

pic
Editor guide