2026-10-12 訂正:欠落したJSX、recipeのimport、生成先への手書き、CSSの適用手順、JIT・型制約・性能の説明を訂正しました。個人の移行実績は確認できていないため撤回し、公式資料に基づく移行候補として説明します。
移行する理由を先に決める
Tailwindはユーティリティクラス、Pandaはスタイルオブジェクトやrecipeを中心に記述します。どちらもビルドでCSSを生成できます。Tailwind公式はソース内のクラスを検出する仕組みを説明しています。「JITですべてのutilityをビルドする」という旧比較は誤りでした。
Pandaの型補完・token・variantを共通設計へ組み込みたい場合は候補になります。Tailwindで既に十分な運用ができている場合は、変更費用やplugin依存、採用版、チームの習熟も比較します。単に新しいという理由だけで全面移行を推奨しません。
Pandaの「zero runtime」は主に実行時のCSS生成・挿入を不要にする説明です。通常のcss()等のクラス組立用JavaScriptまで必ずゼロになるわけではありません。Next.js統合公式は通常の小さなruntimeと、source transformによる置換も区別しています。Tailwindから変えるだけで必ず初期表示が速くなるとは保証できません。
Next.jsへの接続:codegenだけでは終わらない
以下は公式の現在のv2資料に沿う、src/app構成の候補です。既存の設定をバックアップし、採用版とlockfileを固定して、初期化が作る差分を確認します。以下のインストールやアプリ実行は今回行っていません。
npm install -D @pandacss/dev
npx panda init --postcss
現在の初期化が用意するpreset設定を維持します。src以外にもコンポーネントがあればincludeへ追加し、既存PostCSS設定へpluginを統合します。既存ファイルを丸ごと置換しません。
// panda.config.ts
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
presets: ['@pandacss/preset-base', '@pandacss/preset-panda'],
preflight: true,
include: ['./src/**/*.{js,jsx,ts,tsx}'],
exclude: [],
outdir: 'styled-system',
theme: { extend: { tokens: {
colors: { brand: { value: '#3b82f6' } }
} } }
})
// postcss.config.cjs:既存pluginがあれば保持して統合する
module.exports = { plugins: { '@pandacss/dev/postcss': {} } }
package.jsonのscriptsへ次を統合します。JSONへコメントは書けません。
{
"scripts": {
"prepare": "panda codegen",
"dev": "next dev",
"build": "panda codegen && next build",
"start": "next start"
}
}
src/app/globals.cssにはlayer順を置き、src/app/layout.tsxからimportします。この経路ではPostCSSがCSS抽出を担います。型/helper生成だけをするcodegenとCSS生成・配信を区別します。
@layer reset, base, tokens, recipes, utilities;
// src/app/layout.tsxの既存importへ追加
import './globals.css'
旧panda watchはpanda --watchへ訂正します。CLI watch方式を選ぶ場合は、生成stylesheetを適切な相対pathからimportし、PostCSS方式との二重出力を避けます。ここではPostCSS方式を使うためwatchを追加しません。Tailwindとの併用中はreset・layer・selectorの競合を比較し、移行が終わる前に旧CSSを削除しません。
JSXを含む比較例
次はsrc/components/Card.tsxを想定しています。rootのstyled-systemへの相対pathもファイル位置で変わります。Tailwind版とPanda版は色や間隔の見た目が等しいか別途確認してください。
import { css, cva } from '../../styled-system/css'
import type { ReactNode } from 'react'
export function TailwindCard() {
return <article className="rounded-lg bg-white p-4 shadow-md">
<h2 className="text-xl font-bold">カードタイトル</h2>
<p className="mt-2 text-gray-700">説明文</p>
</article>
}
export function PandaCard() {
return <article className={css({ rounded: 'lg', bg: 'white', p: '4', shadow: 'md' })}>
<h2 className={css({ fontSize: 'xl', fontWeight: 'bold' })}>カードタイトル</h2>
<p className={css({ mt: '2', color: 'gray.700' })}>説明文</p>
</article>
}
const buttonStyle = cva({
base: { rounded: 'md', fontWeight: 'semibold', px: '4', py: '2' },
variants: {
visual: {
solid: { bg: 'blue.500', color: 'white', _hover: { bg: 'blue.600' } },
outline: { bg: 'transparent', color: 'blue.500', borderWidth: '1px', borderColor: 'blue.500' }
}
},
defaultVariants: { visual: 'solid' }
})
export function Button({ children, visual = 'solid' }: {
children: ReactNode; visual?: 'solid' | 'outline'
}) {
return <button type="button" className={buttonStyle({ visual })}>{children}</button>
}
Recipe公式に沿い、この例はgenerated cssからcvaをimportして、手書きのコンポーネントファイルへ置きます。旧recipeを@pandacss/devからimportする例は撤回しました。共有するconfig recipeはdefineRecipeで設定のtheme.recipes等へ登録し、codegen後のhelperを使います。styled-systemは生成先であり、そこへ独自recipeを手書きして再生成で失う構成を避けます。
汎用patternという旧importも撤回しました。必要な場合に生成された具体的なpattern helperを選び、任意の名前が存在するとは扱いません。単純なlayoutならまずcssで十分か判断します。
型と静的抽出の限界
型制約の公式説明ではstrictTokensは追加設定です。既定でtoken以外をすべて拒否するという旧説明を訂正します。有効化してもtokenと結び付くpropertyを対象とし、raw値のescape hatchもあります。これはruntime入力の安全性や画面の正しさを保証する機能ではありません。
動的スタイル公式に沿い、利用者入力やAPI応答の値をそのままcss({ bg: runtimeColor })へ渡しても、必要なCSSが生成されるとは限りません。有限の候補はliteral/recipe variantで明示します。任意の値が必要ならCSS変数等を検討し、許可値・範囲・適用先を検証します。staticCssで広く生成すると出力量も増えるため測定します。
tokenの命名だけを合わせても、breakpoint、line-height、reset、色、forms/typography pluginの挙動が同じとは限りません。旧textColor utilityの不完全なalias例や、h1だけでTypography相当になる説明は撤回しました。既存の必要な表示・interactionを抽出し、個別に移植します。
自動変換は差分レビューの補助
tw2pandaのREADMEで確認できるCLI例です。採用するversionのhelpと対応範囲を確認します。
npx tw2panda rewrite src/components/Button.tsx
npx tw2panda convert -s "p-4 text-blue-500 hover:bg-gray-100"
rewriteは既定で標準出力へ結果を出し、ファイルへ書くには-wが必要です。-sはshorthandを指定します。旧説明の「実行するとファイルが変わる」「常に短縮propertyで出る」を訂正しました。変換後のimport、custom token/plugin、動的class、responsive・状態selectorを確認し、変換できたことを移行完了と扱いません。今回はツールをインストール・実行していません。
完了を判断するための検証
掲載TS/TSX/JavaScriptの構文とJSONのparseは確認しました。Pandaのcodegen、生成型との型検査、Next build、CSS生成、ブラウザ表示は未実行です。生成されるclass名は設定や版で変わるため、旧記事のCSS文字列を正確な出力として残していません。
本移行では一つの画面で、buildと型検査、CSSが配信されること、mobile/desktop、hover/focus/disabled、dark mode、keyboard、reset競合を確認します。bundle/CSS量と表示指標を同条件で比較し、戻せる段階ごとに進めます。今回の例だけで完全移行や高速化が実証されたとは扱いません。
この記事を書いた人✏️@YushiYamamoto
ITPRODX.com代表 / AIアーキテクト
Next.js / TypeScript / n8nを活用した自律型アーキテクチャ設計を専門としています。
日々の自動化の検証結果や、ビジネス側の視点(ROI等)に関するより深い考察は、以下の公式サイトおよびnoteで発信しています。