Setup Next JS typescript project with styled components

November 1, 2022  •   3 min read



Problem

css modules or even scss are good but let's face it, styled components beats them. It's easy to maintain and write the styles in styled components. Let's begin.

Setup next typescript project

Refer https://nextjs.org/docs

npx create-next-app@latest --typescript

By default the project will come with css modules. Start the server and you should see this page.



Install dependencies for styled components

npm i styled-components --save
npm i @types/styled-components --save-dev

Now let's change our homepage to use styled component. Replace index.tsx in pages directory with following code and restart your server.

import styled from 'styled-components';

const HomeWrapper = styled.div`
  display: flex;

  h1 {
    color: red;
  }
`

export default function Home() {
  return (
    <HomeWrapper>
      <h1>Styled Components</h1>
    </HomeWrapper>
  )
}

You might see this screen with the error.



  Warning: Prop `className` did not match. Server: "sc-gswNZR iiTRcP" Client: "sc-bcXHqe cYnOsz"
  at div
  at O (webpack-internal:///./node_modules/styled-components/dist/styled-components.browser.esm.js:31:19750)

In order to resolve this server side rendering hydration issue with styled components we need to install a babel plugin.

npm i babel-plugin-styled-components --save-dev

You can refer more about this here Styled Components: ssr

Restart your server. If you're lucky you won't need to do anything else and everything will work just fine depending on what nextjs version you're using.




Interestingly, I wasn't lucky while setting up my site but I noticed it worked just like that while writing this blog. In case it doesn't work, we'll need to write our own .babelrc file to use this plugin.

NextJS have changed some stuff after version 13. Following stuff might come in handy for older versions.

create .babelrc file in the root directory and add the following code.

{
  "presets": ["next/babel"],
  "plugins": [
    ["styled-components", { "ssr": true,"displayName": true, "preprocess": false }]
  ]
}

Next we we'll need to write custom document file rendered on the server. Add _document.tsx file in pages directory and add the following code.

Also you can use this file to add analytics scripts, fonts etc. on all pages. Just add your stuff in the Head tag in this file.

import Document, {Html, Head, Main, NextScript } from 'next/document';
import { ServerStyleSheet } from 'styled-components';


export default class MyDocument extends Document {
  static async getInitialProps(ctx: any) {
    const {renderPage} = ctx;
    const initialProps = await Document.getInitialProps(ctx)

    // Step 1: Create an instance of ServerStyleSheet
    const sheet = new ServerStyleSheet();

    // Step 2: Retrieve styles from components in the page
    const page = renderPage((App: any) => (props: any) =>
      sheet.collectStyles(<App {...props} />),
    );

    // Step 3: Extract the styles as <style> tags
    const styleTags = sheet.getStyleElement();

    // Step 4: Pass styleTags as a prop
    return { ...initialProps, ...page, styleTags};
  }

  render() {
    const {styleTags} = this.props as any;
    return (
      <Html>
        <Head>
          {styleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}


I hope this was helpful 🤓🤓