DEV Community

Cover image for The best styling options for Next.js
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

The best styling options for Next.js

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:

Text Highlighting

Using global CSS styling in Next.js

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;
    }
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
      )
    }
Enter fullscreen mode Exit fullscreen mode

Pros to using global styling in CSS

  • No setup required
  • Perfect for small projects like POC

Cons

  • All styling is contained in a single file
  • It’s difficult to scale as your project grows

Using CSS modules with Next.js

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;
    }
Enter fullscreen mode Exit fullscreen mode

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>
      )
    }
Enter fullscreen mode Exit fullscreen mode

Pros to using CSS modules for styling

  • No setup required
  • Components can split styling
  • Can be used with global styling
  • Unlike global styling, conflicts between classes are avoided

Cons

  • No dynamic styling (e.g., based on a status like loading, error, success, etc.)

Next.js styling with Sass

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
Enter fullscreen mode Exit fullscreen mode

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;
    }
Enter fullscreen mode Exit fullscreen mode

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>
      )
    }
Enter fullscreen mode Exit fullscreen mode

Pros:

  • Easy setup with Next.js
  • CSS compatible
  • Interesting features for complex styling needs like variables, nesting, etc.

Cons:

  • Time lost learning new functionalities of SASS

More complex than CSS Styling with Styled-JSX

The 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>
      )
    }
Enter fullscreen mode Exit fullscreen mode

Pros to using Sass with Next.js

  • No setup required
  • Dynamic styling
  • Portability: your code (CSS and JS) is contained in one file and can therefore be moved easily

Cons

  • Not as much support as other CSS-in-JS libraries (7k stars on Github vs. 36k for styled-components)
  • Code readability can be more difficult when mixing CSS and JS

Using styled-components

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
Enter fullscreen mode Exit fullscreen mode

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()
        }
      }
    }
Enter fullscreen mode Exit fullscreen mode

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>
    }
Enter fullscreen mode Exit fullscreen mode

Pros of using styled-components with Next.js

  • Built using React in mind and has lots of community support
  • Dynamic styling based on props
  • Customizable and reusable like React components (i.e., <Title /> instead of <h2 className="title"/>)

Cons

  • Additional configuration necessary for server-side rendering frameworks like Next.js
  • Bit of a learning curve getting used to the functionalities
  • When compiled, styled-components classes become random (i.e., css-1kybr8i), making debugging harder

Emotion

Another 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
Enter fullscreen mode Exit fullscreen mode

To use styled components, you should also install the required library:

    npm install --save @emotion/styled
    # or
    yarn add @emotion/styled
Enter fullscreen mode Exit fullscreen mode

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>
    }
Enter fullscreen mode Exit fullscreen mode

Pros to using Emotion

  • Server-side support and easy setup with Next.js
  • With @emotion/styled, you get all the advantages of styled components
  • Many packages for different needs: CSS, styled, Jest, native, etc.

Cons

  • Like styled-components, Emotion generates random class names, making debugging with the element inspector harder
  • A bit of learning curve getting used to the functionalities

Styling Next.js with Tailwind CSS

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
Enter fullscreen mode Exit fullscreen mode

Run tailwindcss init to generate the required files:

    npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

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: [],
    }
Enter fullscreen mode Exit fullscreen mode

In styles/global.css, add the Tailwind CSS directives:

    @tailwind base;
    @tailwind components;
    @tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
      )
    }
Enter fullscreen mode Exit fullscreen mode

Pros to using Tailwind CSS

  • Lots of pre-defined classes whether for padding, margin, color, and more
  • Once familiar with the classes, the styling process becomes faster
  • Compiled CSS is automatically optimized by removing unused CSS

Cons

  • No separation of content vs. structure because CSS and HTML are combined
  • Time needed to learn all the different classes

Conclusion

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!


LogRocket: Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket signup

LogRocket is like a DVR for web and mobile apps, recording literally everything that happens on your Next 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.

Top comments (1)

Collapse
 
vortovor profile image
Cgr Gnctrk

Thanks. Is it possible to declare two class names on the element by using module.css ?