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)