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 calledstyles
.
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! 😃
Top comments (0)