Why We Chose PandaCSS for Next.js CSS-in-JS

KO

Original: Read on Medium This is a migrated version of the Medium post for this blog.

PandaCSS: Why We Chose This CSS-in-JS Library

Introduction

As SSR and server-first frameworks became mainstream, many CSS-in-JS libraries either became unstable or harder to use reliably. I experienced this firsthand with styled-components, including performance issues.

I considered Tailwind CSS, a widely adopted static class generator, but it has a learning curve because you need to internalize pre-defined utility class names.

PandaCSS, on the other hand, gives us CSS-in-JS ergonomics without runtime overhead.

At build time, it generates a styled-system directory and precompiles styles, including dynamic style patterns, into classes. That makes runtime styling practical while avoiding runtime style generation costs.

PandaCSS still has tradeoffs. For example, generated class names can be long, which can be inconvenient for E2E tests or certain analytics use cases. Similar issues can appear in other utility-based systems too.

Even with these tradeoffs, we decided to use PandaCSS. Team familiarity was also a factor, and since we had used styled-components, PandaCSS's style-function approach was a good fit.

Advantages of PandaCSS

  1. Type safety: PandaCSS integrates deeply with TypeScript, which helps catch styling errors earlier and improves maintainability.
  2. Build-time CSS generation: CSS is generated at build time, so there is no runtime overhead. This helps improve load performance and reduce bundle impact.
  3. Framework compatibility: It works well with modern frameworks such as Next.js, Remix, and Vite, including SSR environments.
  4. Utility-first composition: Small utility units make complex styling easier to compose, improving readability and maintainability while avoiding runtime style costs.

Setup and Usage

panda.config.ts configuration file

PandaCSS is configured through panda.config.ts. In this file, you define output directories, theme extensions, and inclusion paths.

import { defineConfig } from '@pandacss/dev';
import { textStyles } from './theme/textStyle';
 
export default defineConfig({
  preflight: true, // Reset base browser styles
  include: ['./src/**/*.{js,jsx,ts,tsx}', './pages/**/*.{js,jsx,ts,tsx}'],
  exclude: [],
  theme: {
    extend: {
      textStyles,
    },
  },
  outdir: 'styled-system',
});

PandaCSS Layer Rules

You can control styling priority by importing globals.css, and each layer can override styles when needed.

PandaCSS uses CSS layer rules to manage style architecture in a structured way. This makes priority clearer and styling behavior more flexible.

@layer reset, base, tokens, recipes, utilities;
  • reset: Resets default HTML styles.
  • base: Contains global styles.
  • tokens: Contains semantic and design tokens.
  • recipes: Contains component-level styles.
  • utilities: Contains utility-class styles.

I will cover layers in more detail in a follow-up post.

Example Code

The example below uses PandaCSS's css function. It receives a style object and returns a className string.

import { css } from '../styled-system/css';
 
const styles = css({
  backgroundColor: 'gainsboro',
  borderRadius: '9999px',
  fontSize: '13px',
  padding: '10px 15px'
});
 
<div className={styles}>
  <p>Hello World</p>
</div>

PandaCSS supports shorthand style properties and strong TypeScript integration, which helps produce safer and more efficient code. It also leverages modern CSS capabilities for better maintainability and reusability.

Conclusion

PandaCSS is a strong CSS-in-JS option for teams that want lower runtime cost and maintainable style architecture. It has broad framework compatibility and works well in SSR contexts.

After using it for about six months, even before full stable release, I found it practical for production use. It is actively maintained with frequent updates.

At this point, I think spending less energy debating CSS library choices and more energy solving higher-level product and engineering problems creates more value. If you are choosing a CSS library, I recommend one that is easy and broadly applicable.

For more details and examples, visit the official PandaCSS site.