Created by Vercel, Next.js is a JavaScript framework based on React. With its ability to offer static and server rendering, its popularity quickly shot up amongst developers.
What’s less known is that Next.js offers many ways to support CSS in your application. Whether you prefer utility CSS with its classes or prefer CSS-in-JS, Next.js has you covered. In this tutorial, you will discover a few ways to implement styling in your Next.js application. Let’s implement a styled text that turns red when the user hovers it:
The easiest way to write CSS in a Next.js application is through its global stylesheet. Every newly created Next.js project comes with a styles
folder and inside it, a global.css
stylesheet.
As a result, you can start writing CSS right away with no setup required. For example, in styles/global.css
, you can add this:
.paragraph { font-size: 16px; text-align: center; } .paragraph:hover { color: red; }
The styles created in global.css
will then apply to your entire application.
To do so, this stylesheet can only be imported in _app.js,
as the App
component initializes all the pages in your Next.js pages.
In a new Next.js project, it is done for you, but if you don’t already have an _app.js
file in your pages
folder, create one. Once done, import your new global stylesheet:
//In _app.js, import your global stylesheets import '../styles/globals.css' function MyApp({ Component, pageProps }) { return <Component {...pageProps} /> } export default MyApp
You can then use those classes in your application. For example, on your homepage in pages/index.js
:
export default function Home() { return ( <p className="paragraph">I am styled with a global css stylesheet</p> ) }
As convenient as a global stylesheet can be when just starting, this file can become less manageable as your application grows.
Also, Next.js is a component-based framework, meaning it is easier to split styling for respective components. For instance, if you have a component for your footer, it would be easier to import a stylesheet containing the styling of this component, but nothing more. Enter CSS modules!
If you are not familiar, CSS modules allow you to isolate your CSS by creating files for style-specific components. They are very easy to use, as they are simple CSS but have the module.css
extension instead. Like the previous method, it requires no setup and can be used in addition to a global stylesheet.
Here is an example of a Home.module.css
:
//Home.module.css .paragraph { font-size: 16px; text-align: center; } .paragraph:hover { color: red; }
In your component, pages/index.js
, you can then import your stylesheet and use it:
import styles from '../styles/Home.module.css' export default function Home() { return ( <p className={styles.paragraph}>I am styled with CSS modules</p> ) }
If basic CSS is not enough and you find yourself in search of a CSS framework, look no further than Sass. Describing itself as “CSS with superpowers“, it is a popular framework compatible with CSS and offers lots of cool features like variables, nesting, and mix-ins. Here’s a GitHub repo for our example project.
Using Sass with Next.js is straightforward. All you have to do is install the library:
npm install sass # or yarn add sass
Once done, you can start writing Sass code. Don’t forget the .scss
or .sass
file extensions! Here is an example of Sass code in styles/Home.module.scss
:
//Home.module.scss $hover-color: red; .paragraph { font-size: 16px; text-align: center; } .paragraph:hover { color: $hover-color; }
Similar to using CSS modules, we’ll import the new file to style our application once we finish writing our CSS.
import styles from '../styles/Home.module.scss' export default function Home() { return ( <p className={styles.paragraph}>I am styled with SASS</p> ) }
Pros:
Cons:
More complex than CSS
Styling with Styled-JSXThe previous three methods covered the best styling options if you prefer Utility CSS. But perhaps you are more of a CSS-in-JS kind of person. In which case, Styled-JSX might be up your alley.
Built by Vercel, the founder of Next.js, Styled-JSX allows developers to write CSS in their JavaScript code. There is no setup necessary, and it works out of the box.
Here is an example of Styled-JSX:
export default function Home() { return ( <div className="paragraph"> <style jsx>{` .paragraph { font-size: 16px; text-align: center; } .paragraph:hover { color: red; } `}</style> <p>I am a component styled with Styled-JSX</p> </div> ) }
Styled-JSX can be convenient to start with, but hard to debug as your application grows. As a result, you might be tempted by styled-components.
Styled-components is very practical, as it was created for React. It allows developers to create components with style automatically injected. You can also make use of props for dynamic styling (i.e., for disabled or hover state). Check out a sample project here.
To use it in Next.js, start by installing the library:
npm i styled-components # or yarn add styled-components
The only drawback of using styled-components is that it was made for React, meaning it’s geared for client-side rendering. At the moment, server-side rendering is not supported out of the box.
However, this is easily fixed by creating a new pages/_document.js
file and adding this:
import Document, { Head, Html, Main, NextScript } from 'next/document' import { ServerStyleSheet } from 'styled-components' export default class MyDocument extends Document { render() { return ( <Html lang="en"> <Head></Head> <body> <Main /> <NextScript /> </body> </Html> ) } 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() } } }
Once done, you can import the library into your components and start using it. For example, in pages/index.js
, you can create a Paragraph
styled component for your homepage:
import styled from 'styled-components' const Paragraph = styled.p` font-size: 16px; text-align: center; &:hover { color: ${props => props.hoverColor}; } ` export default function Home() { return <Paragraph hoverColor="red">I am a component made with Styled Components</Paragraph> }
<Title />
instead of <h2 className="title"/>
)css-1kybr8i
), making debugging harderAnother CSS framework created with React in mind is Emotion. It offers a CSS prop (to pass style directly to an element) and styled components. An additional benefit of Emotion is that server-side rendering works out of the box. Check out GitHub here.
To use Emotion in your Next.js application, you first need to install the library:
npm install --save @emotion/react #or yarn add @emotion/react
To use styled components, you should also install the required library:
npm install --save @emotion/styled # or yarn add @emotion/styled
Then, you can start writing your styled components directly. In pages/index.js
, here is an example of a Paragraph
component:
import styled from '@emotion/styled' const Paragraph = styled.p` font-size: 16px; text-align: center; &:hover { color: ${props => props.hoverColor}; } ` export default function Home() { return <Paragraph hoverColor="red">I am a component made with Emotion (Styled Components)</Paragraph> }
Using PostCSS, Next.js also offers support to popular tools such as Tailwind CSS. By installing Tailwind as a PostCSS plugin, it will scan your code and generate the correct stylesheets for you. Not only is it fast, but it also comes with a list of utility classes for you to choose from (i.e., spacing, text size, and more).
To use it with Next.js, start with installing tailwindcss
, postcss
, and autoprefixer
as peer dependencies:
npm install -D tailwindcss postcss autoprefixer
Run tailwindcss
init to generate the required files:
npx tailwindcss init -p
This command generated two files:
postcss.config.js,
which you don’t need to touch
tailwind.config.js
In the latter, add your template paths. These configs will tell Tailwind CSS what code to scan to generate the stylesheet:
module.exports = { content: [ "./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {}, }, plugins: [], }
In styles/global.css
, add the Tailwind CSS directives:
@tailwind base; @tailwind components; @tailwind utilities;
If you are using a newly created Next.js project, this will be done for you, but, if not, make sure that pages/_app.js
imports your styles/global.css
stylesheet:
import '../styles/globals.css' function MyApp({ Component, pageProps }) { return <Component {...pageProps} /> } export default MyApp
You can now start using Tailwind CSS. In pages/index.js
, if you want to create a centered paragraph with a hover state, you can do so like this:
export default function Home() { return ( <p class="text-center text-lg hover:text-red-600"> I am a component made with Tailwind CSS </p> ) }
Choosing a styling option depends on many factors: the size of your project, time, and, mostly, personal preferences. Thankfully, whether you prefer utility CSS or CSS-in-JS, Next.js offers built-in support for CSS.
In this tutorial, you discovered some of those. First, you learned how to write CSS with global stylesheets or CSS modules. For developers with more complex needs, you also saw how to use Sass with Next.js.
Then, for those who prefer CSS-in-JS, we covered some methods such as Styled-JSX, styled-components, and Emotion.
Finally, you also learned that Next.js offers support for tools such as Tailwind CSS with PostCSS, which benefits developers who want access to a design system with thousands of pre-built CSS classes. Thanks for reading!
Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next.js app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.
The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.
Modernize how you debug your Next.js apps — start monitoring for free.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowconsole.time is not a function
errorExplore the two variants of the `console.time is not a function` error, their possible causes, and how to debug.
jQuery 4 proves that jQuery’s time is over for web developers. Here are some ways to avoid jQuery and decrease your web bundle size.
See how to implement a single and multilevel dropdown menu in your React project to make your nav bars more dynamic and user-friendly.
NAPI-RS is a great module-building tool for image resizing, cryptography, and more. Learn how to use it with Rust and Node.js.
6 Replies to "The best styling options for Next.js"
I think you make a mistake in the cons to of css modules.
Potential styling conflicts when used in large projects.
Not really css are managed by JavaScript for give scope (always have a hash to prevent collision)
No dynamic styling (e.g., based on a status like loading, error, success, etc.)
This would be implemented with data-attributes.
And another pro is that CSS Modules is more fast than another styles solutions.
I… totally did. 🤦‍♀️ Thank you for bringing that to my attention. I will get that fixed.
As for data-attributes, I couldn’t find a good and easy example. The best I could find was Sasha’s guide to write CSS components using data attributes (https://sacha.me/articles/css-data-components). Compared to Emotion where you can just pass in props and any conditional styling you want, using data-attributes sounds complicated.
Nothing complicated about using data attributes. CSS (especially SCSS) modules are boss. Never understood the whole appeal of “single file components”. One tab for html/jsx another for css and you’re clean and in business. No need to get out of sync with the rest of the web and constantly change to a new hipper syntax each year. Have you thought of the headaches of opening up a tailwind or css-in-js site 5 years from now when whatever library du jour you used is long defunct and a security liability?
“`css
div[data-invalid] {
color: red;
}
div:not([data-invalid]) {
display: none;
}
“`
“`javascript
Name is a required field
“`
Thank you for the example, Unleashit.
Hi Anthony,
Thanks for reading this blog post and catching this error! We’ve updated the post with the corrected information.
Sass can also be used with CSS modules if defined as .module.scss or .module.sass