Radix UIが作った新しいUIライブラリのThemesがとても良い！

# はじめに
[Radix UIのPrimitives](https://www.radix-ui.com/primitives)を使ったことはありますか？
ヘッドレスなUIコンポーネントを提供してくれるライブラリとして有名で単にRadix UIとも呼ばれます(似たようなライブラリとしては最近でた[Ark UI](https://ark-ui.com)などがあります)。
このようなライブラリはUIを見た目と振る舞いに分けたうちの振る舞いだけを実装したコンポーネントを提供しています。そのため、Material UIやChakra UIのようなスタイリングも含むUIコンポーネントライブラリでは強制されていたスタイリング方法から抜け出して自由度を持ったスタイリングができるとして人気です。

そんなライブラリを開発していたRadix UIですが、新たに[`Themes`](https://www.radix-ui.com/)と呼ばれるコンポーネントライブラリの提供を2023年の8月8日から開始しました。

この記事では`Themes`の使い方と特徴を簡単に紹介します。

## Themes
`Themes`の説明が遅れてしまいました。`Themes`はUIコンポーネントライブラリです。
`Primitive`とは異なりスタイリングも振る舞いも兼ねた`Material UI`や`Chakra UI`に近いライブラリです。

コンポーネントの設計指針は以下のように掲げられております。
> An open-source component library optimized for fast development, easy maintenance, and accessibility.
迅速な開発、容易なメンテナンス、アクセシビリティのために最適化されたオープンソースのコンポーネントライブラリです。

スタイリングは純粋なCSSを用いて行われており、他のUIコンポーネントライブラリでよく使われている`emotion`などに依存していないところも特徴です。

さらにRSCにも対応しています。対応していると言っても全てのコンポーネントに`use client`ディレクティブを用いた暫定的な対応ではなく、クライアント側のコンポーネントとサーバー側のコンポーネントをちゃんと使い分けた実装がなされています。

https://twitter.com/radix_ui/status/1689258626102239232?s=46&t=ckJQiHnfLPloxEpmMekaOw

`Themes`には便利なページがあります。

https://www.radix-ui.com/themes/playground

全体でカスタマイズ可能な項目を選択しながらコンポーネントの一覧を見ることができるplaygroundです。一覧性が高く、標準からカスタマイズした姿が見られるのでとても感動しました。開発する前に全貌を把握できるのでとても便利です。

### 導入する
Nextjsのプロジェクトを用いて導入を進めてみます。他のプロジェクトでも同様に導入可能です。

アプリの下準備としてNextjsのプロジェクトを作ります。
```sh
pnpm create next-app
```
いくつか質問されますがほとんどはデフォルトで回答します。`tailwindcss`は利用しないので`no`を選択します。
`no`を選択してもCSS Modulesを用いたプロジェクトが建つので`globals.css`や`page.modules.css`を削除します。さらに`layout.tsx`からファイルの参照を消して、`page.tsx`からファイルの参照とJSXを書き換えるために空にしておきます。
```tsx:src/app/page.tsx
export default function Home() {
  return <></>
}
```
これでNextjsアプリの作成とスタイリングの排除が完了しました。

次に`Themes`を導入していきます。
まずはパッケージのインストールです。
```sh
pnpm install @radix-ui/themes
```
続いて、`layout.tsx`にアプリ全体で設定したい`Themes`が提供するCSSを配置します。
```tsx
import '@radix-ui/themes/styles.css';
```
他のフレームワークの場合はどこにアクセスした時も呼び出すところに配置してください(remixだと`root.tsx`とか)。

そして、`Themes`全体のカスタマイズのために`Theme`コンポーネントを`layout.tsx`に定義します。

```tsx:src/app/layout.tsx
import { Theme } from '@radix-ui/themes';
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import '@radix-ui/themes/styles.css';

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
    　　<body className={inter.className}>
　　　　　　　　　　　　<Theme>
　　　　　　　　　　　　　　{children}
　　　　　　　　　　　　</Theme>
　　　　　　　　　　</body>
    </html>
  )
}
```

これで準備は完了です。好きなコンポーネントを`@radix-ui/themes`から呼び出して利用していきましょう！
```tsx
import { Flex, Text, Button } from '@radix-ui/themes';

export default function MyApp() {
  return (
    <Flex direction="column" gap="2">
      <Text>Hello from Radix Themes :)</Text>
      <Button>Let's go</Button>
    </Flex>
  );
}
```

![スクリーンショット 2023-08-10 19.41.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/ea13e407-c679-359d-392f-b5231f9408b9.png)

### Themeによるカスタマイズ
`Theme`コンポーネントではアプリ全体の基本となる色、カラーモード、ビジュアルスタイルを設定します。
`Theme`コンポーネントの設定をするときは`ThemePanel`コンポーネントを用いることをお勧めします。
`ThemePanel`コンポーネントは`Theme`コンポーネントでカスタマイズ可能な項目を変更するパネルを画面に表示させられます。
![スクリーンショット 2023-08-10 19.13.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/616ef3cf-e9b9-0ccc-a1ea-875c4939c19c.png)
開発初期の段階ではかなり助かる機能だと考えています。

#### 色
アプリケーションの中心となる色としてアクセントカラーを、グレースケールの中心カラーとしてグレーカラーを選択します。

```tsx
<Theme accentColor="lime" grayColor="olive">
```
アクセントカラーは全23種類あります。選択した色に対応して文字の色も決まります。
グレーカラーは全6種類あります。
アクセントカラーとグレーカラーの組み合わせに悩んだ場合は[おすすめの組み合わせ](https://www.radix-ui.com/colors/docs/palette-composition/composing-a-palette#natural-pairing)が提供されているので参考にしてください。

#### カラーモード
デフォルトではライトモードに設定されています。`Theme`の`appearance`を`dark`に設定することでダークモードに変更できます。
```tsx
<Theme accentColor="lime" grayColor="olive" appearance="dark">
```

カラーモードの設定はクライアント側で要素に対するクラスの追加によって行われるのでエラーが発生します。
以下のように`html`に`suppressHydrationWarning`を追加して抑制させてください。
```tsx
<html lang="en" suppressHydrationWarning>
```
#### カードなどの背景
`Themes`ではデフォルトの状態ではカードやテーブルの背景は半透過しています。
![スクリーンショット 2023-08-10 19.29.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/f278174d-cbef-45c8-d8ca-39d3c7b20b64.png)
透過させたくない場合は`panelBackground`で`solid`にすることで等価を失わせられます。
```tsx
<Theme panelBackground="solid">
```
![スクリーンショット 2023-08-10 19.30.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/78dc0285-9840-1de8-86f9-c75bb0dba75c.png)
#### 角丸
コンポーネントの境界の外側の角に対する丸みを決めます。
```tsx
<Theme radius="medium">
```

### コンポーネント
コンポーネントは大きくレイアウトとタイポグラフィ、コンポーネントの3つに分けられます。

レイアウトは`Box`や`Flex`のようなコンポーネントを組み合わせるときや整理する時に利用するコンポーネントです。

タイポグラフィは`Text`や`Heading`のようなテキストを表すためのコンポーネントです。

コンポーネントは`Accordion`や`CheckBox`のような機能を持ったコンポーネントです。

レイアウトに`Section`があったり、タイポグラフィに`Em`があったりhtmlの要素のセマンティクスに配慮しやすいコンポーネントが多くアクセシビリティへの配慮を感じました。

#### スタイリング
コンポーネントへのスタイリングは引数を用いて行います。量が多いので頭出しだけですが、`Box`に対して`4px`のpaddingを設けたい場合は以下のように設定します。

```tsx
<Box p="1" />
```
`p`に`1`を指定して`4px`のpaddingを実現しました。この値は`Themes`で指定されたCSS変数によって定まりました。
このケースでは[デフォルトのファイル](https://github.com/radix-ui/themes/blob/main/packages/radix-ui-themes/src/styles/tokens/space.css#L2)にある`--space-1`を元に`4px`となりました。
```css:space.css
.radix-themes {
  --space-1: calc(4px * var(--scaling));
  --space-2: calc(8px * var(--scaling));
  --space-3: calc(12px * var(--scaling));
  --space-4: calc(16px * var(--scaling));
  --space-5: calc(24px * var(--scaling));
  --space-6: calc(32px * var(--scaling));
  --space-7: calc(40px * var(--scaling));
  --space-8: calc(48px * var(--scaling));
  --space-9: calc(64px * var(--scaling));
}
```

このようにコンポーネントで指定する値の多くは`Themes`が定義したCSS変数によって決まります。それを`theme-config.css`ファイルに上書きして定義してカスタマイズできます。`theme-config.css`は`layout.tsx`のようなルートファイルで`@radix-ui/themes/styles.css`と合わせて呼び出す必要があります。

```css:theme-config.css
.radix-themes {
  --space-1: 4px;
}
```

CSS変数がまとまったデフォルトの設定は[こちら](https://www.radix-ui.com/themes/docs/theme/token-reference#tokens)に書かれています。

## おわりに
新たなUIコンポーネントライブラリ`Themes`を紹介しました。playgroundや`ThemePanel`などスタイリングに関するDXがとても良いところが印象的でした。
後発のライブラリですので、これまでのUIコンポーネントライブラリや`Primitives`を開発して来たプラクティスが生かされていますし、RSC対応もちゃんとされています。
さらに、既存のUIコンポーネントライブラリの多くが採用している`emotion`を利用していないのでサーバー側でのレンダリングにおけるパフォーマンス上の問題も生じません。

このようなところから、これからのUIコンポーネントライブラリとして台頭してくると考えています。
UIコンポーネントライブラリを新しく選定する機会がありましたらぜひ採用したいと思いました。皆さんも採用を検討してみてはいかがでしょうか。