Park UI + Panda CSSでReact Server Components(RSC)に対応

<ins>2024/11/11更新 Park UI v0.42(2024/08/08リリース)の変更への対応と、Chakra UI v3への言及を追記しました。</ins>

ヘッドレスコンポーネントライブラリArk UIのコンポーネントをゼロランタイムCSS in JSでスタイリングしたUIコンポーネントライブラリ**Park UI**を使ってNext.jsのApp Routerに対応する記事です。

https://park-ui.com/

デモページ  
https://nextjs-park-ui-on-vercel.vercel.app/

デモページのリポジトリ  
https://github.com/cieloazul310/nextjs-park-ui-on-vercel

## 動機

[Next.js] v13で導入された[App Router]では[React Server Components(RSC)][React Server Components]の理解が必須となります。しかしながら[Material-UI]や[Chakra UI]など従来のReactコンポーネントライブラリのスタイルシステムは[Emotion]ベースであることが多く、2024年2月現在でRSCへの対応が不十分であり、新たにApp Routerを学びたい場合にUIデザインは障壁となります。

## Park UIとは

**Ark UI**のコンポーネントを**ゼロランタイムCSS in JS**でスタイリングしたUIコンポーネントライブラリです。通常UIコンポーネントライブラリはReactやVueなど特定のフレームワークにのみ対応していますが、Park UIはReact, Vue, Solidで使うことができます。というのも、Park UIは**ドキュメントからコンポーネントのコードをコピー&ペーストして使用する**からです。

Park UIの特徴としてスタイルシステムは[Tailwind CSS]と[Panda CSS]のどちらか好きな方を選択することができます。

### Ark UIとは

[Ark UI]は[Chakra UI]の開発チームによる**ヘッドレスコンポーネントライブラリ**です。ヘッドレスコンポーネントライブラリとはスタイルを持たないコンポーネントライブラリのことで、コンポーネントからスタイルを排除しアクセサビリティの実装やインタラクティブな機能面を抜き出すことで、ユーザーが柔軟にカスタマイズすることができます。

https://ark-ui.com/
 
### Panda CSSとは

Chakra UIの開発チームによる**ゼロランタイムCSS in JSライブラリ**です。Tailwind CSSに大きな影響を受けていますが、Tailwind CSSと決定的に異なる点は、独自のクラス名を覚える必要はなく、従来のCSS in JSのようにオブジェクトとして堅安全性を保ちながらスタイルを記述できる点です。

https://panda-css.com/

### 各ライブラリの関係性

- [Chakra UI][Chakra UI]: Reactコンポーネントライブラリ
- [Zag][Zag]: Chakra UIが開発する**ロジック・ステート制御のライブラリ**
- [Ark UI][Ark UI]: Chakra UIが開発するZagをベースとした**ヘッドレスコンポーネントライブラリ**
- [Panda CSS][Panda CSS]: Chakra UIが開発する**ゼロランタイムCSS in JSライブラリ**
- [Park UI][Park UI]: Ark UIをPanda CSSまたはTailwind CSSでスタイリングしたコンポーネントライブラリ(Chakra UI開発チーム所属の個人によるサードパーティ)

<del>将来的にはChakra UI v3がZag, Ark UI, Panda CSSで構成される予定です。Park UIは現時点でPanda CSSを使ってRSCに対応する有効な手段であると同時に、Chakra UI v3の導入の準備にもなります。</del>
<del><ins>将来的にChakra UIはZag, Ark UI, Panda CSSで構成される予定です。ただし開発中のChakra UI v3は引き続きEmotionをベースとすることが明言されています。</ins></del>
<del><ins>2024/03/29追記 やはりChakra UI v3はZag, Ark UI, Panda CSSで構成されるようです。</ins></del>

<ins>2024/11/11追記 Chakra UI v3がリリースされました。Chakra UI v3は従来通りEmotion(及びランタイムCSS in JS)ベースで構成されていますが、Panda CSSのスタイルシステムを部分的に取り入れています。</ins>

https://www.adebayosegun.com/blog/the-future-of-chakra-ui

https://www.adebayosegun.com/blog/chakra-panda-ark-whats-the-plan

https://www.chakra-ui.com/blog/00-announcing-v3

## どのような場合に向いているか

- Next.jsのApp Router、React Server Components(RSC)に対応したい
- ゼロランタイムCSS in JSを使いたい
- でも基礎的なコンポーネントを一から設計するのは面倒
- Tailwind CSSの記法が苦手 (Panda CSSを使いたい)

自分はTailwind CSSの記法が苦手なのでPanda CSSが使えるライブラリを探した結果Park UIに行き着きましたが、Tailwindに馴染みがある方であればPark UIに影響を与えたライブラリに[shadcn/ui]があり、こちらの方が日本語の情報も多いと思われます。

## 環境

ここではNext.js(App Router) + Panda CSSの環境を前提としています。

<ins>2024/11/11更新 各パッケージのバージョンを更新しました</ins>

```md
- @ark-ui/react: ^4.3.0
- @pandacss/dev: ^0.47.1
- @park-ui/panda-preset: ^0.42.0

- next: 15.0.3
- react: ^18
- react-dom: ^18
```

## 準備

0. Next.js(App Router)とPanda CSSの導入
1. インストール
2. Panda ConfigファイルにPark UIプリセットを設定
3. コンテキストファイルを配置
4. TSConfigのパス(任意)と`park-ui.json`を設定

### 0. Next.js(App Router)とPanda CSSの導入

https://panda-css.com/docs/installation/nextjs

### 1. インストール

ここからはPark UI公式ドキュメントのGetting Startedに沿って説明します。

```sh
# Ark UIをインストール
npm install @ark-ui/react

# Park UIのPanda Presetを作成
npm install --save-dev @park-ui/panda-preset
```

https://park-ui.com/react/docs/overview/getting-started

### 2. Panda ConfigファイルにPark UIプリセットを設定

ここではPanda CSSを使っているので、`panda.config.ts`にPark UIプリセットを追加します。

```ts
// panda.config.ts
import { defineConfig } from "@pandacss/dev";
import { createPreset } from "@park-ui/panda-preset";

export default defineConfig({
  preflight: true,
  presets: [
    "@pandacss/preset-base", 
    createPreset({
      accentColor: "blue",
      grayColor: "sand",
      borderRadius: "xl",
    }),
    // or "@park-ui/panda-preset"
  ],
  include: ["./src/**/*.{js,jsx,ts,tsx}"],
  exclude: [],
  jsxFramework: "react",
  outdir: "styled-system",
});
```

この例では`createPreset`関数を使ってアクセントカラーに`blue`、グレーカラーに`sand`、borderRadiusに`xl`を設定していますが、Park UIデフォルトのプリセットを使う場合は`"@park-ui/panda-preset"`という文字列を配列に記述すればOKです。

Park UIのプリセットによってPanda CSSの`recipes`や`patterns`を生成し、それをコンポーネントで利用するという仕組みです。

https://park-ui.com/react/docs/theme/colors

### 3. コンテキストファイルを配置

まずプロジェクト内のPark UIのコンポーネントを置くディレクトリと、Park UIコンテキストを置くディレクトリを決定します。この例では以下のように設定します。

- Park UIコンポーネント: `src/components/ui`
- <del>Park UIコンテキスト: `src/lib`</del>

<del>Park UIコンテキストのディレクトリ(`src/lib`)に`create-style-context.tsx`を作成し、Park UIドキュメントからコピー&ペーストします。React Server Components(RSC)を使う場合は冒頭に`"use client"`ディレクティブを記載します。</del>  
<ins>2024/11/11更新 Park UI v0.42からPark UIコンテキストディレクトリが、Park UIコンポーネントディレクトリ(この例では`src/components/ui`)傘下に移動しています。</ins>

https://park-ui.com/react/docs/overview/getting-started

### 4. TSConfigのパス(任意)と`park-ui.json`を設定

この設定はPark UI CLIを使う場合必要になります。

#### TSConfig(任意)

```json
{
  "baseUrl": ".",
  "paths": {
    "@/*": ["./src/*"],
    "styled-system/*": ["./styled-system/*"]
  }
}
```

#### `park-ui.json`

`park-ui.json`は後述するPark UI CLIを使用する場面で必要になります。Park UI CLIによる自動コピー機能を使わない場合は必要ありません。<del>`importAliases`には3.で決定したPark UIコンポーネントディレクトリと、Park UIコンテキストのディレクトリを設定します。</del>  
<ins>2024/11/11更新 Park UI v0.42から`outputPath`にPark UIコンポーネントディレクトリを指定するように変更されています。</ins>

```json
{
  "$schema": "https://park-ui.com/registry/latest/schema.json",
  "jsFramework": "react",
  "outputPath": "./src/components/ui"
}
```

## コンポーネントの使い方

Park UIのコンポーネントは通常のUIライブラリとは異なり、**コンポーネントのコードをディレクトリにコピー&ペーストして使用します**。例えばPark UIの`<Button>`コンポーネントを使う場合、Park UIのウェブサイトに記載されているコードをコピーし、`button.tsx`としてディレクトリの任意の場所に置く必要があります。

この例では`src/components/ui`をPark UIコンポーネントのディレクトリとしているので、`src/components/ui/button.tsx`というファイルを作成して、下記リンクの「Installation」>「1. Add Component」のコードをコピー&ペーストします。

Button - Park UI

https://park-ui.com/react/docs/components/button

具体的な使い方は各コンポーネントのUsageのコードを参考にするといいでしょう。

### コンポーネントのProps

各コンポーネントのPropsの内容はArk UIのAPI Referenceを参照することになります。Park UIドキュメントの各コンポーネントのヘッダ画面にリンクが配置されています。

### Park UI CLIによる自動コピー

Park UI CLIでは前述の通りコマンドラインによってコンポーネントの自動コピーが可能です。Park UI CLIを使うには`park-ui.json`が必要です。

```sh
# park-ui.jsonを生成
npx @park-ui/cli init

# buttonコンポーネントをコピー
npx @park-ui/cli add button

# 全てのPark UIコンポーネントをコピー
npx @park-ui/cli add --all
```

https://park-ui.com/docs/panda/overview/cli

### Park UI 使用における留意点

<del>
#### React Server Components (RSC)を使う場合

Park UIコンテキストに依存するコンポーネントには先頭に`"use client"`ディレクティブを記載する必要があります。Park UI CLIを使用する場合は、`park-ui.json`の`useReactServerComponents`を`true`にしておくと自動コピーの際に必要なコンポーネントに対して`"use client"`ディレクティブを自動で付けてくれます。
</del>

#### 独自のSemantic Tokens

Park UIはPanda CSSやTailwindのTokensの値を使って独自のSemantic Tokensを生成しています。ただしPanda CSSやTailwindのTokensを改変する形であるため、これらのツールを既に使ったことがある人にとっては少し引っかかるポイントになります。

- パレットを12段階に新たに正規化している (例: `red.50`が`red.1`になる)
- パレットの`shades`がダークモードで明暗が逆転する (例: ライトモードの`red.12`は暗色だがダークモードの`red.12`は明色)

この仕様は[Radixのカラーシステム](https://www.radix-ui.com/colors)に則っているようです。

https://park-ui.com/react/docs/theme/semantic-tokens

### カスタマイズの方法

`panda.config.ts`で既存のテーマを拡張(`extend`)することでPark UIのプリセットをカスタマイズすることができます。

https://park-ui.com/react/docs/theme/customize

## まとめ

<del>Chakra UIは[2023年中にゼロランタイムCSS in JSの導入とRSCに対応するv3をリリースする予定でした](https://www.adebayosegun.com/blog/chakra-panda-ark-whats-the-plan)が、2024年2月現在v3はリリースされていません。</del>
<del><ins>Chakra UIは将来的に自前のゼロランタイムCSS in JSであるPanda CSSを導入する予定です。</ins></del>
<del><ins>2024/03/29追記 やはりChakra UI v3はPanda CSS + Ark UIで構成され、そしてコンポーネントデザインにはPark UIが採用されるようです。</ins></del>

<ins>2024/11/11追記 Chakra UI v3はPanda CSSのスタイルを部分的に導入しています。またArk UIが導入されており、Park UIと同様、プロジェクト内にコンポーネントディレクトリを生成するデザインシステムが導入されています。</ins>

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Excited to bring together all the projects we&#39;ve been working on into <a href="https://twitter.com/chakra_ui?ref_src=twsrc%5Etfw">@chakra_ui</a> v3<br><br>🟡 Styling API from Panda<br>🟠 Headless primitives from Ark<br>⚫️ Component recipes from Park UI<br><br>Coming together nicely 🤩. We&#39;re pretty close! <a href="https://t.co/1mgdyL8vSK">pic.twitter.com/1mgdyL8vSK</a></p>&mdash; Sage ⚡️ (@thesegunadebayo) <a href="https://twitter.com/thesegunadebayo/status/1773403593086844939?ref_src=twsrc%5Etfw">March 28, 2024</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

また[Material-UIも2024年6月までにv6をリリースし、ゼロランタイムCSS in JSの導入とRSCに対応する予定](https://mui.com/blog/2023-material-ui-v6-and-beyond/)です。

今後主流になっていくと思われるゼロランタイムCSS in JSやRSCの準備運動としてPark UIを使ってみてはいかがでしょうか。

## リンク

https://park-ui.com/

https://panda-css.com/

https://ark-ui.com/

https://zagjs.com/

https://www.chakra-ui.com/

https://www.adebayosegun.com/blog/chakra-panda-ark-whats-the-plan

[Chakra UI]: https://chakra-ui.com/
[Park UI]: https://park-ui.com/
[Panda CSS]: https://panda-css.com/
[Ark UI]: https://ark-ui.com/
[Zag]: https://zagjs.com/
[shadcn/ui]: https://ui.shadcn.com/
[Material-UI]: https://mui.com/
[Next.js]: https://nextjs.org/
[App Router]: https://nextjs.org/docs/app
[React Server Components]: https://nextjs.org/docs/app/building-your-application/rendering/server-components
[Emotion]: https://emotion.sh/
[Tailwind CSS]: https://tailwindcss.com/