ProNextJS
    Professional Next.js Course
    Loading price
    30-Day Money-Back Guarantee
    lesson

    Styling with Material UI's Pigment CSS

    Jack HerringtonJack Herrington

    Now we'll look at using Pigment CSS, a build-time CSS solution that works seamlessly with React Server Components.

    Comparing Pigment with Material UI

    Material UI is a popular component framework for Next.js applications that use the Pages Router. However, it doesn't work natively with React Server Components. This is because Material UI is based on Emotion, which uses context for theming. Since React Server Components can't handle context, Material UI components need to be client components to manage their own styling. This is a fundamental issue that can't be fixed with a spot fix, so the team behind Material UI created Pigment CSS.

    Installation

    As usual, the installation instructions for Pigment CSS can be found in the official documentation, but we'll work through them here as well.

    First, we need to install the @pigment-css/react library:

    pnpm add @pigment-css/react
    

    Then we'll update the next.config.mjs file to import the Pigment CSS plugin. The nextConfig object is currently empty, but we'll wrap it in the withPigment function to set up Pigment CSS which will be the default export:

    // inside next.config.mjs
    
    import { withPigment, extendTheme } from "@pigment-css/nextjs-plugin";
    
    /** @type {import('next').NextConfig} */
    const nextConfig = {};
    
    export default withPigment(nextConfig);
    

    Implementing Dark and Light Mode

    In layout.tsx, import the base styles from Pigment as well as its css function:

    // inside layout.tsx
    import { css } from "@pigment-css/react";
    
    import "@pigment-css/react/styles.css";
    

    Styles can be defined by using either Pigment's object syntax or the backtick syntax Here's how the html class would be defined using both methods:

    const DARK = "@media (prefers-color-scheme: dark)";
    
    // Using object syntax
    const htmlClass = css(({ theme }) => ({
      backgroundColor: "white",
      color: "black",
      [DARK]: {
        backgroundColor: "black",
        color: "white",
      },
    }));
    

    Then the htmlClass can be added to the html element in the RootLayout component:

    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode;
    }) {
      return (
        <html lang="en" className={`${inter.className} ${htmlClass}`}>
          <body>{children}</body>
        </html>
      );
    }
    

    Saving our work, Polypane should show the dark background is working as expected.

    Styling the Main Content

    Over in the page.tsx file, we'll bring in the styled and css functions from Pigment::

    // inside page.tsx
    import { styled, css } from "@pigment-css/react";
    

    This time we'll use the backtick syntax to specify CSS for the mainClass:

    const mainClass = css`
      margin: 0 auto;
      max-width: 960px;
      font-family: sans-serif;
      display: flex;
      flex-wrap: wrap;
    `;
    

    It's generally a good idea to stick with one syntax for your entire application, but Pigment CSS allows you to choose the one that works best for you. There's no runtime performance issue here since all the styles are generated at build time.

    Next, we'll create a new Card component that will be a div element that has CSS applied to it with the styled function:

    const MOBILE = "@media screen and (max-width: 768px)";
    
    const Card = styled("div")`
      padding: 0.2rem;
      width: 33%;
      max-width: 33%;
      ${() => MOBILE} {
        width: 100%;
        max-width: 100%;
      }
    `;
    

    We'll stop here so you can update the existing Home component to use apply the mainClass styles and use the new Card component. In the next video, we'll review how it's done.

    Transcript

    If you remember back to the start of this, I talked about Material UI and how Material UI is a very popular component framework for Next.js applications. In the Pages Writer, it was pretty much the de facto that we would go to, particularly for enterprise applications. Just an excellent component set that was freely available, lots of great documentation. Now the problem was with the App Writer, those components didn't work natively with RSC or React Server components. And it was really a fundamental issue.

    Material UI was based on top of emotion, and emotion supported theming even if you didn't use it. And that theming was managed via context, which is a very sane thing to do. And the problem is that RSEs can't handle context. And so every component that would include a Material Y component or manage its own styling using Emotion would need to be a client component in order to get that context to do that styling. So how do they fix it?

    Well, you can't fix a system like that with a spot fix, unfortunately. You have to come up with an entirely new system because it's just kind of fundamentally broken in that model. And what they came up with was a new system called Pigment CSS. So that's what we're going to look at in this video. We're going to take Pigment CSS, which is a build time CSS solution, and apply it to our example to turn it into a fully fledged application.

    So the first thing we need to do is install it. So there's a link to our installation instructions in the instructions down below. There is a section on installing using Next.js. I'm probably going to follow those instructions as is. I did a PR to make sure that they worked.

    But then, you know, I'm gonna make a change to go from npm to pnpm as I always do. Let's go over and go into our application. I'm gonna add the pigment CSS React library, and I'm gonna add the Next.js plugin as a development dependency. Then I'm gonna go over and adjust my next configuration to bring in with pigment and then I'm going to wrap my next JS configuration which is currently empty in the with pigment call And that's going to set up Pigment. It's really that easy.

    It's actually a quite nice installation process. Now let's start by going to our layout and handling the dark light mode switch again. Go into layout. We're going to bring in our base styles for Pigment. Then we're going to bring in the CSS function from Pigment CSS React.

    That's how we're going to define our CSS classes now down here right above our root layout and then I'll create the HTML class now there are multiple ways to define a CSS class using pigment one way is to use the object syntax like I'm doing here You can also use the backtick syntax where you really use CSS inside of that string. So really depends on how you like it. If you want the kind of style version of this where you use background color and camel case, then use the object variant. And if you're more comfortable specifying in CSS, just like you would in the .css file, then just use the backtick syntax. Now with the HTML class, I'm gonna go down here into our HTML and apply it.

    And I apply it by just simply grabbing HTML class. Again, like other solutions, that becomes a string. We'll fire up our development server and then see how it looks. And there we go. Now I've got the light dark mode switch.

    So it looks like pigment is installed correctly and we've got our light dark mode switch going on. So that's great. Now let's go and style the main. So back over in our original studio code, I'm going to go page. This time I'm going to bring in both CSS and style and I'll show you how to use both of those.

    Specify the class of the main, I'm going to use the backtick syntax this time just to kind of show you the different flavors that we have. Really depends on you which one you like, but I would recommend actually just picking one and staying with that for your entire application. There's no runtime performance issue here. All of this is done at build time, so whether you specify using object syntax or the CSS syntax, it all ends up as CSS in the end. For the card, I'm going to use the style variant.

    So I'm going to create a component for a card. It's going to be based on div, and then I'm going to apply the styles again using the backtick syntax. Now I'm going to stop here, and you get to take that main class and that card and apply it to the application. I'll see you on the other side of the video, and I can show you how I do it.