KENTEM TechBlog

建設業のDXを実現するKENTEMの技術ブログです。

Panda CSS🐼でコンポーネントライブラリを作る ── RSC時代の選定理由から実運用まで

この記事は、 テックブログ強化月間 リレーブログ企画2026 参加の記事です。

2年ほど前、社内のデザインシステムを基にフロントエンド向けのコンポーネントライブラリを実装することになり、スタイリングライブラリとして最終的にPanda CSSを採用しました🐼

本記事では、Panda CSS(以下 Panda)の選定背景から、理解の前提となる周辺知識、既存プロジェクトへの導入のしやすさ、基本的な使い方、運用上の注意点等を順に紹介していきます。

Pandaを理解するための前提知識

本題の前に、Pandaの設計思想を理解するうえで前提となる概念を3つだけ整理しておきます。これらは他のCSSツールにも共通する話なので、知っておくと議論が早くなります。

PostCSS

PostCSSは、CSSをJavaScriptで変換するためのプラグイン基盤です。Sass/Lessのような独立した構文ではなく、CSSをASTにパースしてプラグインで書き換え(例えばベンダープレフィックス付与や圧縮等)、再度CSSに戻すツールチェインです。

.foo { color: red; }

   ↓ PostCSS parse

AST (Root → Rule → Declaration)

   ↓ plugins (autoprefixer, nesting, ...)

変換後のAST

   ↓ PostCSS stringify

.foo { color: red; -webkit-... }

Tailwind、Panda、CSS Modules、autoprefixer などはすべてPostCSSプラグインとして動作します。Panda導入時に postcss.config.js@pandacss/dev/postcss を入れる必要があるのは、PandaがPostCSSパイプラインの一段として動くためです。 すでにPostCSSが組み込まれているNext.js / Vite / Astroのようなフレームワークにプラグインを1行追加するだけで導入できるのはメリットの一つですね。

カスケードレイヤー

CSSの「C」はCascade(カスケード)の意味で、複数のスタイル定義が衝突したときの採用ルールは、

  1. 重要度 (!important)
  2. 詳細度 (#id > .class > tag)
  3. 記述順 (後勝ち)

で決まります。これだけだと、「ライブラリのデフォルトスタイル」と「自分が書いたスタイル」が衝突したとき、詳細度で負けると上書きできなくなり、!importantを乱発するハメになります。

カスケードレイヤー (@layer) は、詳細度や記述順より上位にある「層」の優先順位でスタイルの強弱をコントロールする仕組みです。

Pandaが生成するCSSは以下のレイヤー構造になっています。

レイヤー Pandaでの役割 優先度
reset CSSリセット 最弱
base グローバルなベーススタイル
tokens デザイントークン(CSS変数の定義)
recipes コンポーネントスタイル
utilities css()で書いた個別スタイル 最強

これにより、

  • リセットCSSがコンポーネントスタイルを意図せず上書きしない
  • css({ color: 'red' })で個別に当てたスタイルは、Recipeのデフォルトを必ず上書きできる
  • 詳細度の戦争が起きない

という安心感が生まれます。このレイヤー設計のおかげで、詳細度の戦争が起きず、既存プロジェクトへの導入でも効いてきます。

cva (class-variance-authority)

Tailwindコミュニティで広く使われている cva は、「バリアントを持つコンポーネントのクラス名を組み立てるユーティリティ」です。

import { cva } from 'class-variance-authority'

const button = cva('inline-flex items-center rounded font-semibold', {
  variants: {
    variant: {
      solid: 'bg-indigo-500 text-white',
      outline: 'border border-indigo-500 text-indigo-500',
    },
    size: {
      sm: 'px-3 py-1.5 text-sm',
      md: 'px-4 py-2 text-base',
    },
  },
  defaultVariants: { variant: 'solid', size: 'md' },
})

cva を使うと、variants で定義した「軸」の組み合わせをタイプセーフに扱えます。 デザインシステム作りで非常に強力ですが、TailwindプロジェクトではTailwind本体・cva・tailwind-mergeを組み合わせるのが定番で、依存も設定も増えがちです。

PandaのRecipesは、このcva相当の機能を標準装備していると捉えると分かりやすいです。defineRecipeの戻り値はそのままタイプセーフな関数になり、追加ライブラリは不要です。

なぜPandaなのか🐼

選定に関する条件

コンポーネントライブラリを作る上で、以下を満たすスタイリングライブラリが必要でした。

  • 既存プロジェクトへの導入のしやすさ: 既にTailwindやstyled-componentsで書かれたコードベースに後から入れても破綻しない
  • 学習曲線が低い: ある程度のCSSの知識があればスタイルを容易に変更できる
  • デザイントークンの管理のしやすさ: 色、スペーシング、タイポグラフィを宣言的に、型安全に扱える
  • バリアント管理: PrimaryやSecondaryといったスタイルの違いを破綻なく表現できる
  • コンポーネントのカスタマイズのしやすさ: プロジェクトごとに異なる「ここだけ余白を詰めたい」「角丸を強めに」といった要求に柔軟に応えられる
  • テーマ切り替え: ライト/ダーク、ロール別など、複数のテーマを宣言的に扱える
  • パフォーマンス: ランタイムオーバーヘッドを最小化し、特にRSC/App Router時代の前提に乗れる(ゼロランタイムであること)
  • 開発体験: 型補完、エディタ拡張、ESLintによる規律がある程度整っている
  • ライブラリが今後もしっかりメンテナンスされていくか

選定の候補としては、Tailwind CSSvanilla-extractCSS Modules、そしてPandaでした。 他にもmetaが出したStyleXKuma UI等のゼロランタイムライブラリはあったのですが、当時出たばかりだったので採用は見送りました。

styled-components / EmotionといったランタイムCSS-in-JSは、表現力が高い反面、ランタイムオーバーヘッドによるパフォーマンス問題やバンドルサイズの増加といった問題に加え、React Server Components (RSC) との相性が悪い問題がありました。当時はNext.js App Routerを使ったプロジェクトが増えることが予想されていたので、その辺りのかみ合わせが良くないライブラリはそもそも省くことにしました。 この点はまた別の記事で詳しく掘り下げようと思っています。

そもそも何者なのか

Pandaは、Chakra UIのチームが開発している ビルド時に CSS を生成する型安全な CSS-in-JS フレームワーク です。「CSS-in-JS」と銘打たれていますが、ランタイムで JavaScript が CSS を注入する従来型の CSS-in-JS(styled-components 等)とは異なり、ビルド時に静的なCSSを吐き出します。(ゼロランタイム)

比較対象との違い

Tailwind CSS

Tailwind CSSは素晴らしいユーティリティクラスのセットを提供してくれますが、デザインシステムの観点では以下のような課題があります。

  • クラス名の文字列を扱う前提で設計されているため、TypeScriptの型チェックが効かない(プラグインで補強は可能)
  • 複雑なバリアントを持つコンポーネントを作るとき、cva などの追加ライブラリを組み合わせる必要がある
  • JSXのクラス属性が長くなりがちで、可読性が低下する
  • ユーティリティクラスの学習曲線が高め(?)
  • 既存プロジェクトに導入する際に、スタイリングがバッティングする可能性があった(現在はカスケードレイヤーの仕組みがあるはず)

正直、好みや慣れの部分が多いにありますが、Tailwindは視覚情報の多くをclassNameに集中させるため、コンポーネントの構造を読むときにスタイルにノイズを感じる場面が増えがちです。 個人的にTailwind CSSは別に嫌いではないですが、誰でもカスタマイズしやすくすることを考えると、ユーティリティクラスよりもCSSそのままに近い形でのスタイリングがいいのではとなりました。 とはいえNext.jsは標準でTailwindを推奨してきますし、AIもTailwindでのスタイリングが多いように感じます。また、Pandaに比べるとやはり利用者が多い分サンプルとなるコードもかなり多いです。 無難な選択肢として依然として強い立場にあるのかなと思います。

vanilla-extract

vanilla-extractも同じくゼロランタイムで型安全なソリューションで、思想として近い部分があります。ただ、

  • スタイル定義を .css.ts ファイルに分離する必要がある
  • レシピ機能はあるものの、デザイントークンの扱いはPandaの方が体系的
  • パターン(stack, hstackなど)のような便利な抽象が標準で用意されていない

という違いがあります。なるだけスタイル定義とマークアップは近くに置きたかったというのが大きいですね。 ぱっと修正したいときに、スタイルファイルとマークアップであまり行き来したくないのではと考えたためです。 またレシピを使いたいときは、別でライブラリのインストールが必要だったりするのも微妙でした。 書き心地はかなりPandaに似ているため、最悪Pandaがダメでもこちらに引っ越せばよいかぐらいには思った気がします🍨

CSS Modules

CSS Modulesはこちらが本体となる仕様です。 ざっくり言うとCSSファイル内のクラス名をローカルスコープに変換する、というルールを定義しているだけです。実行時のランタイムは存在しません。 バニラCSSとほとんど同じ書き心地で学習曲線がとても低いのと、主要なフレームワークにほぼほぼ標準でサポートされているのがかなりの強みです。 私も大好きなのですが、コンポーネントライブラリを作る上では、テーマやデザイントークンを扱うときは別途CSS変数やSassの変数を準備する必要があり、ここが難点で断念しました。

Pandaの優れている点(デザインシステム視点)

ここを土台に選定理由&特徴をまとめると、以下になります。

  1. デザイントークンが第一級市民: 色、スペーシング、タイポグラフィなどを theme.tokens で一元管理でき、すべてのスタイル定義から型安全に参照できる
  2. セマンティックトークン: ライト/ダークモードや複数テーマの切り替えを、トークン定義レベルで宣言的に書ける
  3. Recipes(レシピ): バリアントを持つコンポーネントスタイルを、cva等の追加ライブラリなしに型安全に定義できる
  4. ビルド時抽出 + 静的CSS: ランタイムコストゼロ、RSC対応
  5. JSXスタイルプロップス: <Box p="4" bg="red.500" /> のような記法もオプトインで使える
  6. アトミックCSS生成: 同じスタイルは重複生成されないので、CSSバンドルが膨らまない
  7. カスケードレイヤーで優先順位を整理: 既存スタイルとの共存が破綻しにくい

特にカスケードレイヤーで優先順位を整理されることで、既存のプロジェクトに組み込みやすいというが大きいですね。

既存プロジェクトへの導入とカスタマイズ性

「新規プロジェクトでは強い」だけのライブラリは、現実のチームではなかなか採用しづらいものです。Pandaの良いところは、既存プロジェクトに後から入れても破綻しにくい点にあります。

段階的に共存できる

Pandaは、対象ファイルを include で絞り込めるので、最初から全ファイルを書き換える必要はありません。

// panda.config.ts
export default defineConfig({
  include: ['./src/design-system/**/*.{ts,tsx}'], // 最初はここだけ
  // 段階的に './src/features/**/*.{ts,tsx}' を足していく
})

これによって、

  • 既存のTailwind / styled-components / CSS Modulesと同居したまま、新しいコンポーネントだけPandaで書ける
  • リファクタリングを進めるペースを、チームの体力に合わせて調整できる
  • 「まずデザインシステムのプリミティブだけPanda」「次にfeature単位で置き換え」のような段階導入が現実的

カスケードレイヤーが効いているおかげで、移行途中で tailwind@layer utilitiesとPandaのutilitiesレイヤーが衝突しても、優先順位を意図通りに制御できます。

カスタマイズ性

Pandaは「設定で振る舞いを変える」余地が広く、デザインシステム作りで欲しくなる細かい調整がほぼほぼ設定で完結します。

  • preset 機能: 自社共通の tokens / recipes / patternspreset としてパッケージ化し、複数リポジトリで共有できる(モノレポでも、別リポジトリの社内ライブラリとしてでも)
  • utilities の拡張: 標準にないCSSプロパティを defineUtility で追加できる(例: truncate: { value: ... } のような独自ショートハンド)
  • importMap: styled-system のimportパスを @my-org/design-system のような任意のエイリアスに差し替え可能
  • outdir の変更: 生成物の置き場所をプロジェクト構成に合わせて変えられる
  • hooks API: スタイル抽出のタイミングでカスタム処理を挟める(例: 命名規則の検査、不正なトークン使用のロギング)

あえてパッケージ化しない選択 ── サブモジュール / コードベース取り込み運用

社内デザインシステムの「配布形態」は、Pandaに限らず常に悩ましいテーマです。一般的にはnpm/private registry経由のパッケージ配布が定石ですが、私たちのチームではあえてパッケージ化しない運用を選んでいます。理由はシンプルで、

パッケージ化するとカスタマイズが途端に難しくなる

から、という一点に尽きます。

パッケージ配布が抱える課題

パッケージ化された共通コンポーネントは、

  • プロジェクト固有の小さな調整(余白、角丸、アイコンの差し替え)を入れたくても、ライブラリ側へのPR or ラッパーコンポーネント作成が必要
  • バグや「もう少し」の挙動を、利用側でその場で直せない といった摩擦が積み重なります。デザインシステムコンポーネントとしては、「完成品の配布」より「プロジェクトに寄り添って変化していく基盤」として運用するほうが、現場の生産性が高いと判断しました。

採用している2つの取り込み方式

代わりに状況に応じて以下のどちらかを選択しています。

1. Gitサブモジュールとして取り込む

デザインシステムリポジトリを各プロジェクトのサブモジュールとしてマウントし、Pandaの include でソースを直接参照します。

// 利用側 panda.config.ts
import designSystemPreset from './packages/design-system/preset'

export default defineConfig({
  presets: ['@pandacss/preset-base', designSystemPreset],
  include: [
    './src/**/*.{ts,tsx}',
    './design-system-components/**/*.{ts,tsx}', // サブモジュール内のソース
  ],
})

メリットは、

  • ソースコードがプロジェクト内に存在するので、いつでも読みに行ける・編集できる
  • プロジェクト固有の調整は、利用側からそのプロジェクト用のブランチを切ってもらいそのブランチ内でプルリクを上げる
  • デザインシステム本体の改善は、サブモジュールのコミットを上げてアップストリームに還流できる
  • アトミックCSSはPandaが利用側でビルドするので、プロジェクトで使っているスタイルだけがCSSに乗る(余計なスタイルが入らない)

2. 必要なコンポーネントだけコードベースに直接取り込む

shadcn/ui的な発想で、デザインシステム側に「テンプレート」としてのコンポーネント実装を置いておき、プロジェクトに必要なものだけコピーして取り込む方式です。

# 例: 自前CLIまたは手作業で必要なコンポーネントを持ってくる
cp -r design-system/src/components/Button src/design-system/Button
cp -r design-system/src/components/Modal src/design-system/Modal

取り込んだ後は、

  • RecipeComponent もプロジェクト側のファイルなので、自由に書き換えられる
  • 不要なコンポーネントは取り込まなければ、依存も発生しない
  • コンポーネント単位のカスタマイズが完全に手元で完結」する

この方式は特に、デザインの方向性がプロジェクトごとに大きく異なる場合や、コンポーネント単位の自由度を最大化したい場合に強力ですが、アップストリームの差分を追いづらくなるのがデメリットです。

この方針とPandaの相性

この「カスタマイズ性最優先」の運用方針と、Pandaの「設定とソースが手元にあれば全てが調整可能」という設計は非常に相性が良いと感じています。presets で共通トークンを継承しつつ、extend でプロジェクト固有のトークン・Recipeを上乗せできるため、「共通基盤の維持」と「プロジェクトごとのカスタマイズ」が両立します。

パッケージ化が悪、ということではありません。組織やプロダクトの規模、デザインの統一度、運用体制によってはパッケージ配布のほうが合うケースもあります。私たちのケースでは、「カスタマイズの摩擦を少なくする」ことを最優先の条件として置いた結果、サブモジュール or コードベース取り込み方式に一旦落ち着きました。


主な使い方

セットアップ

npm i -D @pandacss/dev
npx panda init -p

基本: css 関数

最もシンプルな書き方です。

import { css } from '../styled-system/css'

export function Card() {
  return (
    <div
      className={css({
        bg: 'white',
        p: '4',
        borderRadius: 'md',
        boxShadow: 'sm',
        _hover: { boxShadow: 'md' },
      })}
    >
      Hello Panda
    </div>
  )
}

_hoverのような擬似クラスや、md:, lg:などのレスポンシブも、すべてオブジェクトのキーとして書けます。

デザイントークンの定義

panda.config.tsで、デザインシステムの土台となるトークンを定義します。

import { defineConfig } from '@pandacss/dev'

export default defineConfig({
  theme: {
    extend: {
      tokens: {
        colors: {
          brand: {
            50: { value: '#eef2ff' },
            500: { value: '#6366f1' },
            900: { value: '#312e81' },
          },
        },
        spacing: {
          gutter: { value: '1.5rem' },
        },
      },
      semanticTokens: {
        colors: {
          'bg.canvas': {
            value: { base: '{colors.white}', _dark: '{colors.gray.900}' },
          },
          'fg.default': {
            value: { base: '{colors.gray.900}', _dark: '{colors.gray.50}' },
          },
        },
      },
    },
  },
  conditions: {
    extend: {
      dark: '.dark &, [data-theme="dark"] &'
    }
  },
})

セマンティックトークンを使えば、bg: 'bg.canvas'と書き、<html data-theme="dark">のようなdata属性を定義するだけでライト/ダークが自動的に切り替わります。

Recipes でコンポーネントスタイルを定義

ボタンのようにバリアントを持つコンポーネントは、Recipeとして定義するのが定石です。

// src/recipes/button.recipe.ts
import { defineRecipe } from '@pandacss/dev'

export const buttonRecipe = defineRecipe({
  className: 'button',
  base: {
    display: 'inline-flex',
    alignItems: 'center',
    borderRadius: 'md',
    fontWeight: 'semibold',
    cursor: 'pointer',
  },

  variants: {
    variant: {
      solid: { bg: 'brand.500', color: 'white' },
      outline: { borderWidth: '1px', borderColor: 'brand.500', color: 'brand.500' },
    },
    size: {
      sm: { px: '3', py: '1.5', fontSize: 'sm' },
      md: { px: '4', py: '2', fontSize: 'md' },
    },
  },

  defaultVariants: {
    variant: 'solid',
    size: 'md',
  },
})

設定ファイル側で登録すれば、

import { button } from '../styled-system/recipes'

<button className={button({ variant: 'outline', size: 'sm' })}>Click</button>

のように使えます。variantsizeのキーは型補完が効くので、タイポやミスがコンパイル時に弾かれます。

Patterns でレイアウトを宣言的に

stack, hstack, vstack, grid, flex, circleなどのパターンが標準で用意されており、「よくあるレイアウト」を関数呼び出しで書けます。

import { hstack } from '../styled-system/patterns'

<div className={hstack({ gap: '4', justify: 'space-between' })}>
  <span>Left</span>
  <span>Right</span>
</div>

CSSのFlexプロパティ名を毎回思い出す必要がなくなり、レビュー時の認知負荷も下がります。 またJSX形式で書くこともできます。

運用上の注意点・ハマりポイント

実際に運用してみて気づいた、押さえておくべきポイントです。

動的な値はビルド時に抽出できない

Pandaはビルド時にASTを解析して静的にスタイルを抽出するので、以下のようなコードは抽出されません。

// ❌ 動的な変数はパースできない
const color = isError ? 'red.500' : 'green.500'
<div className={css({ color })} />

代わりに、条件分岐をオブジェクトの中で表現します。

// ✅ オブジェクトリテラル内で条件分岐
<div className={css({ color: isError ? 'red.500' : 'green.500' })} />

これはvanilla-extractやTailwindと同じ制約で、慣れれば自然に書けるようになりますが、styled-components等のライブラリから移行した直後は引っかかりがちです。

compoundVariants の評価順を理解する

variantsで定義したスタイルがマージされたあとにcompoundVariantsのスタイルが上書きされます。スタイルの優先順位を考えるときに、この順序を意識しないと意図しない結果になることがあります。

cvaはatomicクラスを出力するだけで、最終的な勝敗は CSSカスケード(出現順) に依存しますが、

「base → variants → compoundVariants」という流れで後勝ちでスタイルが当たる挙動は、ドキュメントを一度きちんと読んでおくことをおすすめします。

表示順 (CSSロード順) を意識する

Pandaのカスケードレイヤーは「同じドキュメント内でのレイヤー宣言順」によって優先順位が決まります。次の点に気をつけると事故が減ります。

  • エントリCSSの先頭で @layer reset, base, tokens, recipes, utilities; を宣言しないと、レイヤー間の順序が定まらず、Recipe定義よりリセットCSSが後勝ちになる、といった事故が起きる
  • globals.css を読み込む順序: Next.jsの場合、app/layout.tsximport './globals.css' を最初に書く
  • 複数のCSSフレームワークを共存させる場合: Pandaのレイヤーと、TailwindやMUIなど他のCSSの優先順位を @layer明示的にマッピングする

styled-system ディレクトリは生成物

panda codegenで生成されるstyled-system/ディレクトリは コミットしない方が無難 です。.gitignoreに追加し、CIでビルド時に生成する運用が一般的です。コミットするとコンフリクトの嵐になります。

PostCSS と Next.js の組み合わせ

Next.jsで使う場合、postcss.config.cjs@pandacss/dev/postcssを入れる必要があります。Turbopack(next dev --turbo/Next.js 15以降のデフォルト)環境では追加の設定が必要なケースもあるので、公式のNext.jsガイドを必ず確認してください。

特にApp Routerでは、

  • app/globals.css でPandaの @layer 宣言と @import を行う
  • app/layout.tsx の冒頭で import './globals.css'
  • panda codegen をビルドフックの早い段階で実行する (predev / prebuild スクリプトに入れるのが安全)

の3点を最初に押さえておくとハマりにくいです。

Storybookと組み合わせるときの注意

Storybook単体でPandaを使う場合、以下を押さえておくとつまずきにくいです。

  • .storybook/preview.ts でPanda生成のCSSをimport する。import '../src/styles/globals.css' のように、Next.jsアプリと同じエントリCSSを読み込む
  • panda codegen をStorybook起動前に実行しておく(predev 同様、storybook スクリプトの前段で panda codegen を呼ぶ)
  • Storybookのビルダー (Vite / Webpack) によってPostCSS設定の探索パスが違うので、PandaのPostCSSプラグインが効いているかをまず確認する
  • ダークモード切り替えは、Pandaの semanticTokens_dark 条件に合わせて、html[data-theme="dark"][data-color-mode="dark"] などのスコープを panda.config.tsconditions に登録しておくと、Storybookのテーマアドオンと組み合わせやすい
  • Static buildでの利用: npm run build-storybook でアトミックCSSが取りこぼされる場合、include にStorybook用のmdx/storiesも含まれているかを確認する

これらは「PandaがビルドツールとしてのCSS生成に依存している」ことの裏返しで、Storybook側の起動順とPostCSS設定さえ理解すれば落ち着きます。

パッケージ配布する場合は build info の管理が必要

もしnpmパッケージとして共通ライブラリを配布する運用を選ぶ場合、ライブラリ側でpanda.buildinfo.jsonを吐き出して、利用側のpanda.config.tsincludeに含める必要があります。importMapの設定ともセットなので、初回構築は少し迷います。

(私たちのチームは前述の通りパッケージ化を避け、サブモジュール or コードベース取り込み運用にしていますが、組織の規模やデザインの統一度合いによってはパッケージ配布のほうが合うケースもあります。)

クラス名の長大化

アトミックCSSの宿命として、生成されるclassNameがやたら長くなります。本番では問題ありませんが、DevToolsでデバッグするときに「どのスタイルが効いているのか」を追うのに少し慣れが必要です。

JSXスタイルプロップスとclassNameの優先順位

「あるはずのスタイルが当たらない」「同じプロパティを2箇所に書いたらどちらが採用されるのか分からない」というハマりは、Panda CSSでも起きます。代表的な落とし穴を2つ紹介します。

propsとcss()を混ぜたときの優先順位

<HStack className={css({ gap: '80px' })} gap="100px">

このコード、最終的に適用されるのは gap: 80px の方です。Panda CSSはJSXスタイルプロップス → classNamecss() の順でアトミッククラスを生成するため、CSSの記述順で「後勝ち」となり className 側が勝ちます。

細かい話、同じユーティリティに対する複数のアトミッククラスは内部的に cx() でマージされます。同じプロパティを両方に書くと「ぱっと見どちらが採用されるか分からない」状態になるので、混在を避けるかどちらかに統一しておきましょう。

似たスタイルが既に存在していると「上書きされない」ように見える

過去にハマったケースとして、ある要素に色を当てようとしてもなぜか当たらず、トークン名を小文字から(あるいは別の名前に)変えた途端に効いた、という経験がありました。

当時は不思議に思っていましたが、おそらくは以下が起きていたものと推測しています。

  1. 同じ最終CSS出力になるアトミッククラスが、ファイル内の別の場所で既に生成されていた
  2. その近辺で別のスタイル(例えば擬似要素やバリアントによる色定義)が後勝ちでぶつかっていた
  3. トークン名を変えたことで、生成されるクラスがアトミック上「別物」になり、後ろの方に並ぶことになって採用された

要は 「最終CSSの記述順とアトミックCSSの再利用」の組み合わせで詳細度の戦いが起きていただけ、と理解できます。panda debug や生成されたCSSの確認、トークン化の徹底で解決できる類のものです。


おすすめの拡張機能やツール

Panda CSS VSCode

公式が提供している拡張機能です。

ESLint + @pandacss/eslint-plugin

Panda公式のESLintプラグインです。スタイリングのルール化ができるため、ESLintを使っているプロジェクトであれば入れておきましょう。

Panda Studio

デザインシステム全体を探索し理解するための視覚的なインターフェースです。 トークン、セマンティックトークン、レシピ、パターン、条件などを閲覧できて便利です。

CSS Variable Autocomplete

PandaはCSS変数も生成するので、生CSS側で変数を参照したいときに補完が効くと便利です。


まとめ

Pandaは、

  • デザイントークン中心 の設計思想
  • 型安全 な開発体験(Recipesによるバリアント、cva相当の機能が標準装備)
  • コンポーネントのカスタマイズが設定の差分で済む 書き味
  • ビルド時抽出 によるランタイムコストゼロ
  • RSCの恩恵をフルに享受できる という現代的な要件への適合
  • Recipe / Pattern といった抽象が標準装備
  • カスケードレイヤー によるスタイル優先順位の宣言的な制御
  • 既存プロジェクトへの段階導入 が現実的(includeの絞り込み、他CSSとの共存)
  • preset / importMap による配布形態の柔軟さ(サブモジュール取り込み、コードベース取り込み、パッケージ配布、いずれの戦略にも対応できる)

という点で、デザインシステムを真面目に作るチームにとって非常にバランスの良い選択肢かと思います。

ぜひ一度試してみてください!🐼

参考リンク

Panda CSS 公式

周辺技術

おわりに

KENTEMでは、様々な拠点でエンジニアを大募集しています! 建設×ITにご興味頂いた方は、是非下記のリンクからご応募ください。 recruit.kentem.jp career.kentem.jp