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.
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.
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 🤓🤓