DEV Community

Cover image for Exploring Pigment CSS, a zero-runtime CSS-in-JS library by MUI
Megan Lee for LogRocket

Posted on • Originally published at blog.logrocket.com

Exploring Pigment CSS, a zero-runtime CSS-in-JS library by MUI

Written by Ivy Walobwa✏️

CSS-in-JS is a modern approach to styling web applications where CSS is written directly in JavaScript files. This allows CSS styles to be scoped into a component. Many developers, especially in the React community, have adopted the CSS-in-JS approach.

The most popular CSS-in-JS libraries are styled-components and Emotion. MUI, a React component library, recently released a promising, zero-runtime CSS-in-JS library called Pigment CSS. This article will explore the features and benefits of Pigment CSS, offering a comparison to styled-components and Emotion based on performance, features, developer experience, and community support.

Pigment CSS

Pigment CSS Pigment CSS is a zero-runtime CSS-in-JS library maintained by the Material UI team and built on top of WyW-in-JS, or “Whatever-you-want-in-JS.” It extracts colocated styles to their own CSS files at build time. Pigment CSS currently supports Next.js and Vite.

The concept of zero-runtime CSS-in-JS seeks to combine the benefits of CSS-in-JS with the performance benefits of traditional CSS. Here, all styles are compiled to static CSS files at build time, eliminating runtime overhead. This improves performance, especially on initial page loads.

Key features of Pigment CSS

Pigment CSS offers the benefits of CSS-in-JS, such as locally scoped styles and themeability, while avoiding the runtime performance cost typically associated with CSS-in-JS libraries. Some of the key features include:

Zero runtime

Styles are preprocessed during the build phase. No styles are injected and recalculated during runtime. This improves the performance of the application.

Theming

Theming is an optional feature that lets you reuse the same style values across your application. The theme objects are only used at build time and are not included in the final JavaScript bundle.

Integration with build tools

Pigment CSS seamlessly integrates with Next.js and Vite with support for more bundlers in the future. This makes it easy to add Pigment CSS to existing React applications without significant configuration.

Pigment CSS allows you to define CSS in two ways: using object-style syntax, where styles are defined using JavaScript objects, or template-style syntax, where CSS styles are written using template literals.

Comparing Pigment CSS, Emotion, and styled-components

Pigment CSS uses zero-runtime CSS-in-JS, while styled-components uses runtime CSS-in-JS, and Emotion uses runtime CSS-in-JS with options for extracting static styles.

The three libraries can be compared as follows:

  • Performance: Due to its zero-runtime approach, Pigment CSS has reduced runtime performance but increased build time
  • Bundle size impact: Pigment CSS styles compile to pure CSS files at build time, thus having minimal impact on the JavaScript bundle size. On the other hand, styled-components inject styles into the DOM at runtime using JavaScript. Emotion can operate in two modes — pure runtime or static style extraction
  • Dynamic styling: Pigment CSS requires you to declare all styles and account for all combinations of props. styled-components and Emotion excel in applications where styles need to react dynamically to component states or props
  • Developer experience: Pigment CSS offers a developer experience similar to styled-components and Emotion. All three enhance readability by keeping styles closely tied to components. However, a notable difference lies in how the styles are defined: in Pigment CSS, unlike passing props for conditional styling, all style variants must be pre-defined
  • Tooling and ecosystem: styled-components and Emotion have a slight edge in terms of integrations and community resources due to their popularity and longer history in the market

Check out our article comparing styled-components and Emotion for a deeper dive.

Using Pigment CSS

To use Pigment CSS, you must first configure it in your Next.js or Vite application. In this tutorial, we’ll use a Next.js app.

Pigment CSS simplifies the creation of reusable styles and components for your application by providing various APIs. You can use the css API to create reusable styles, the styled API to create a component by passing styles at the end, or the keyframes API to create reusable animation keyframes. A theme object can also be used to reuse the same styling values across your application.

Setting up Pigment CSS

In your Next.js application, install Pigment CSS using the following command:

npm install @pigment-css/react
npm install --save-dev @pigment-css/nextjs-plugin
Enter fullscreen mode Exit fullscreen mode

This command installs the Pigment CSS library and the Next.js plugin.

Next, in your next.config.mjs file, import the withPigment plugin, and wrap the Next.js config as shown below:

import { withPigment } from '@pigment-css/nextjs-plugin';
const nextConfig = {};
export default withPigment(nextConfig);
Enter fullscreen mode Exit fullscreen mode

In your layout.tsx file, import the Pigment CSS stylesheet as shown:

import '@pigment-css/react/styles.css';
Enter fullscreen mode Exit fullscreen mode

With that, you’re ready to make use of Pigment CSS styles.

Basic usage of Pigment CSS

First, we’ll use the css API to create our styles. You can use the template or object syntaxes as shown below:

import {css } from "@pigment-css/react";
// template syntax
const bodyBackground = css`
  background-color: #1D2125;
  color: #fff;
`;
// object syntax
const mainClass = css({
  display: "flex",
  flexDirection: "column",
  alignItems: "center",
  justifyContent: "center",
});
Enter fullscreen mode Exit fullscreen mode

To apply the styles to your DOM element, add the styling as a class name to your element:

<html lang="en" className={bodyBackground}>
</html>
<main className={mainClass}>
</main>
Enter fullscreen mode Exit fullscreen mode

Next, we’ll use the styled API to create our styled components. Here, we create a styled heading and add variants based on the props:

const Heading = styled('div')({
  fontSize: "2rem",
  color: "#9FADBC",
  fontWeight: "bold",
  margin: "1rem",
  variants: [
    {
      props: { variant: 'success' },
      style: { color: '#23AD79' },
    },
    {
      props: { size: 'small' },
      style: { fontSize: '1.5rem' },
    },
  ],
});
Enter fullscreen mode Exit fullscreen mode

We then add the component to our DOM as shown below. One heading uses the base styles while the other heading uses the variant styles on top of the base style:

<Heading>Pigment CSS</Heading>
<Heading variant="success" size="small">Test Styling</Heading>
Enter fullscreen mode Exit fullscreen mode

You can also style your components based on runtime values. The isError prop value is unknown ahead of time. It’s used to style the heading in a callback function:

const Heading = styled('div')({
  fontSize: "2rem",
  color: ({ isError }: { isError: boolean }) => (isError ? 'red' : '#9FADBC'),
  fontWeight: "bold",
  margin: "1rem",
});
Enter fullscreen mode Exit fullscreen mode

The prop value is passed to your component. Here, the heading color is set based on the isError value:

<Heading isError>Test Styling</Heading>
Enter fullscreen mode Exit fullscreen mode

Theming with Pigment CSS

This is an optional feature that allows you to reuse the same styling values across your application using a theme object. You can make use of the extendTheme utility to generate CSS variables from your theme object.

First, for type safety, let’s define our theme interface in a theme.d.ts file as shown below:

import { ExtendTheme } from "@pigment-css/react/theme";
declare module "@pigment-css/react/theme" {
    interface ThemeTokens {
        colorScheme:{
            light: {
                primary: string;
                secondary: string;
                background: string;
                text: string;
                error: string;
            };
            dark: {
                primary: string;
                secondary: string;
                background: string;
                text: string;
                error: string;
            };
        }
    }
    interface ThemeArgs {
        theme: ExtendTheme<{
            colorScheme: "light" | "dark"
            tokens: ThemeTokens
        }>;
    }
}
Enter fullscreen mode Exit fullscreen mode

In the code snippet above, we changed the Pigment CSS theme module. We added our ThemeTokens, which need to match our theme object. We then redefined the ThemeArgs with our color scheme and tokens.

Now, we’ll set the theme module to include in the TypeScript config file:

  "include": ["theme.d.ts","next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
Enter fullscreen mode Exit fullscreen mode

In our next.config file, we added a theme option to the withPigment function. We also used the extendTheme utility to generate CSS variables for our theme:

import { withPigment, extendTheme } from '@pigment-css/nextjs-plugin';
const nextConfig = {};
export default withPigment(nextConfig, {
    theme: extendTheme({
        colorScheme: {
            light: {
                primary: "#9FADBC",
                secondary: '#23AD79',
                background: '#fff',
                text: '#000',
                error: '#CC3131'
            },
            dark: {
                primary: "#9FADBC",
                secondary: '#23AD79',
                background: '#1D2125',
                text: '#fff',
                error: '#CC3131'
            },
        }
    }),
});
Enter fullscreen mode Exit fullscreen mode

We can use the generated theme variables in the css or styled APIs as shown. You can apply styles based on the color scheme by using the prefers-color-scheme media query or the applyStyles functions attached to extendTheme:

// template syntax
const bodyBackground = css`
  background-color: ${({ theme }) => theme.colorScheme.dark.background};
  color: ${({ theme }) => theme.colorScheme.dark.text};
  @media (prefers-color-scheme: light) {
    background-color: ${({ theme }) => theme.colorScheme.light.background};
    color: ${({ theme }) => theme.colorScheme.light.text};
  }
`;
// object syntax
const bodyBackground = css(({ theme }) => ({
  ...theme.applyStyles("light",{
    backgroundColor: theme.colorScheme.light.background,
    color: theme.colorScheme.light.text,
  }),
  ...theme.applyStyles("dark",{
    backgroundColor: theme.colorScheme.dark.background,
    color: theme.colorScheme.dark.text,
  })
})
)
Enter fullscreen mode Exit fullscreen mode

Conclusion

This tutorial explored the new CSS-in-JS library by MUI, Pigment CSS, a zero-runtime library. We discussed its key features and compared it to common CSS-in-JS libraries like Emotion and styled-components. We also went through some basic Pigment CSS library usage such as using the css and styled APIs and theming.

Pigment CSS is still in the early release as of writing this article. The library will have more features and improvements as it grows. Happy coding!

Top comments (0)