2025年08月11日
Panda CSS v1で導入されたJSX Style ContextでSlot Recipeがより便利に
概要
2025年8月、 Panda CSS v1が正式リリースされました 。
このバージョンからJSX Style Context機能が標準搭載され、複合コンポーネントの利用がより柔軟かつ直感的に行えるようになりました。
特に、Slot Recipeを用いた複数部位(slot)を持つコンポーネント開発において、スタイルの一括管理と再利用が容易になります。また、 Ark UI やRadix UIなどのヘッドレスUIライブラリとの統合にも適しています。
JSX Style Context ドキュメント
https://panda-css.com/docs/concepts/jsx-style-context
対象読者
- Panda CSSを利用しており、Slot Recipeの基本を理解している方
- 複合コンポーネントやUIライブラリのスタイリング方法を知りたい方
JSX Style Contextとは
Panda CSSは、 Chakra UI の開発チームが作ったゼロランタイム CSS-in-JSライブラリです。
v1で新たに導入されたcreateStyleContext
関数により、親コンポーネントのpropsに応じて子コンポーネントのスタイルを自動的に切り替えることが容易に可能となりました。
これにより、以下のような直感的な記述が可能になります。
<Card.Root variant="subtle">
<Card.Image src="hoge.png" alt="hoge" />
<Card.Body>Hello, Panda</Card.Body>
</Card.Root>
使い方
1. Slot Recipeを定義してPanda Configに登録
まず、複数のslot(部位)を持つコンポーネントのスタイル定義を行います。その後、Panda ConfigにSlot Recipeを設定してください。
import { defineSlotRecipe } from "@pandacss/dev";
// ["root", "image", "body"]のslotからなるカード
export const card = defineSlotRecipe({
className: "card",
slots: ["root", "image", "body"],
base: {
root: {
display: 'flex',
borderWidth: '1px',
borderRadius: 'lg',
overflow: 'hidden',
bg: 'white',
shadow: 'md',
},
},
variants: {
layout: {
vertical: {
root: { flexDirection: 'column' },
image: { w: '100%', h: 48, objectFit: 'cover' },
body: { p: 4 },
},
horizontal: {
root: { flexDirection: 'row' },
image: { w: 48, h: 'auto', objectFit: 'cover' },
body: { p: 6 },
},
},
},
});
2. createStyleContext
で複合コンポーネントを構築
Panda CSSのビルド後、styled-system/recipes
からSlot Recipeを読み込み、createStyleContext
でスタイル情報を共有できるコンポーネントを作成します。
// src/components/ui/card.tsx
import { card } from "styled-system/recipes";
import { createStyleContext } from "styled-system/jsx";
const { withProvider, withContext } = createStyleContext(card);
// 第1引数に要素名、第2引数にslot名、第3引数に任意でオプションを設定できる
const Root = withProvider("div", "root", { defaultProps: { className: "group" } });
const Image = withContext("img", "image");
const Body = withContext("div", "body");
export const Card = { Root, Image, Body };
3. コンポーネントを使用
import { Card } from "@/components/ui/card";
export function Example() {
return (
<Card.Root layout="horizontal">
<Card.Image src="/panda.png" alt="Panda" />
<Card.Body>Hello, Panda</Card.Body>
</Card.Root>
);
}
Panda CSS Playground
https://play.panda-css.com/DEI09SMXdb
利点
直感的なAPI
既存のUIライブラリに近い構文で記述でき、スタイル定義とコンポーネント構造をシンプルに保てます。
ヘッドレスUIライブラリとの相性
特にArk UIやRadix UIのようなスタイル非依存のUIライブラリとの統合で威力を発揮します。 次項でArk UIをスタイリングするサンプルコードを掲載しています。
コンポーネントライブラリの構築が容易
createStyleContext
は、Panda CSSを使ったUIキット「 Park UI 」や、Emotionベースの Chakra UI でも既に類似の仕組みが採用されています。
今回のv1での導入は、それらの実装アイデアを逆輸入した公式対応といえます。
Ark UI と Panda CSS の組み合わせでのスタイリングパターン
Ark UI はヘッドレス UI コンポーネントライブラリで、ロジックとアクセシビリティを提供します。 見た目のスタイルは自分で決める必要があり、CSS フレームワークやデザインシステムとの組み合わせが前提です。
ここでは、 Panda CSS と組み合わせた スタイリングのコードパターン を紹介します。
実際の UI 表示例ではなく、withRootProvider
や withContext
などを用いたスタイル適用の構造にフォーカスしています。
スタイリング例
// recipes/dialog.ts
import { defineSlotRecipe } from "@pandacss/dev";
import { anatomy as dialogAnatomy } from "@ark-ui/react/dialog";
// Ark UI の Dialog に対応する slot を定義
export const dialog = defineSlotRecipe({
className: "dialog",
slots: dialogAnatomy.keys(),
base: {
root: { display: "flex", alignItems: "center", justifyContent: "center" },
backdrop: { bg: "blackAlpha.700" },
content: { bg: "white", p: "4", rounded: "lg", shadow: "lg" },
title: { fontSize: "lg", fontWeight: "bold" },
description: { color: "gray.600" },
closeTrigger: { position: "absolute", top: "2", right: "2" },
},
});
// components/ui/dialog.tsx
import * as ArkDialog from "@ark-ui/react/dialog";
import { dialog } from "styled-system/recipes";
import { createStyleContext } from "styled-system/jsx";
const { withRootProvider, withContext } = createStyleContext(dialog);
export const DialogRoot = withProvider(ArkDialog.Root, "root");
export const DialogBackdrop = withContext(ArkDialog.Backdrop, "backdrop");
export const DialogPositioner = withContext(ArkDialog.Positioner, "positioner");
export const DialogContent = withContext(ArkDialog.Content, "content");
export const DialogTitle = withContext(ArkDialog.Title, "title");
export const DialogDescription = withContext(ArkDialog.Description, "description");
export const DialogCloseTrigger = withContext(ArkDialog.CloseTrigger, "closeTrigger");
export const Dialog = {
Root: DialogRoot,
Backdrop: DialogBackdrop,
Positioner: DialogPositioner,
Content: DialogContent,
Title: DialogTitle,
Description: DialogDescription,
CloseTrigger: DialogCloseTrigger,
};
この構造のポイント
-
withRootProvider
- コンポーネントツリーのルートにスタイルコンテキストを提供します
- 他の子要素が
withContext
で同じコンテキスト名を使うと、自動でスタイルが共有されます
-
withContext
- 同一コンテキストの
Root
から props や状態 (disabled
,invalid
など) を受け取れます - スタイルやクラスの一貫性が保たれます
- 同一コンテキストの
-
Panda CSS の
recipe
- スタイルのバリエーションを型安全に切り替えることができます
まとめ
- JSX Style Contextは、Slot Recipeを用いた複合コンポーネント開発を劇的に改善します
- Ark UIやRadix UIなどのヘッドレスUIライブラリとの統合に特に有効です
- UIコンポーネントライブラリの設計パターンを、よりシンプルかつ再利用性の高い形で実現できます
いかにもChatGPTが生成した文章となってしまいましたが、createStyleContext
とSlot Recipeの組み合わせは非常に便利という大意を汲み取ってくれると嬉しいです。
リンク
Take Your Aim / Rocket (2025)
Panda CSS
Panda CSSは型安全を保ちながらスタイルを記述することができるCSS-in-JSのパッケージです。
https://panda-css.com/