Server side rendering Styled-Components with NextJS

Using ServerStyleSheets in five minutes

Jessie W.
The Startup
3 min readJun 10, 2020

--

Monitor with css code on the screen
Image source: unsplash

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

{
"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).

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

--

--

Jessie W.
The Startup

“I have no special talent, I am only passionately curious.“— Albert Einstein