なぜ Novi か
React Aria Components と Tailwind で組んだ、きれいなコンポーネント群はもう世の中に足りています。2026 年には shadcn/ui が 8 つのスタイルを出し、React Aria を土台に選べるようにもなりました。色と角丸で差を作るのは、もう誰にでもできます。Novi が持ち込むのは別の4つです。
1. 見た目ではなく、DOM の組み立て方が変わる
Novi の core は 29 個のコンポーネントについて、部位の名前(slot)だけを決め、JSX を決めません。テーマは必須の slot さえ描けば、順序も入れ子も要素の種類も自由です。その結果、同じ <Modal> がテーマごとに別の構造になります。
| テーマ | Modal の構造 | 閉じるの位置 | size の解釈 | コントロール高さ |
|---|---|---|---|---|
| Raster | 中央に浮かぶ。地を暗転 | 右上の ✕ | パネルの幅 | 32 / 40 / 48 |
| Tactile | 下からせり上がるシート | フッターに全幅 | シートの高さ | 40 / 48 / 56 |
| Flatlay | 紙ごと差し替わる(全画面) | 左上の「← 戻る」 | 本文の最大行長 | 28 / 32 / 40 |
3本目のテーマを書き終えた時点で、テーマ同士のコードの一致率は 21 コンポーネント中の最下位2つ(Popover と Toast)で 5 割前後まで割れました。「浮かせるか」という美学の判断が、そのまま構造の差になるためです。だから共通の実装を引き上げる「ファクトリ」は作らないと決めました(ADR-09)。その様子はトップの Modal 三連で見られます。
2. 主張は文章ではなく検査が守る
「AI に書かせても崩れない」は、崩れたら CI が落ちるように作ってあるから言えます。テストが通ることより、壊したら必ず落ちることを確かめてきました。
- slot 契約
- 全テーマの全コンポーネントが core の必須 slot を描いていることを、data-slot 属性で検査します。
- 書いてはいけないクラス
- テーマごとに禁止クラスの一覧を持ち、影の無いテーマに影を書けば lint が落ちます。禁止一覧そのものが「壊したら落ちるか」の変異テストを持ちます。
- 色 8 × 2 × 3 = 48 判定
- カラーウェイをテーマごとに 8 色で止めるのは、全色 × ライト / ダーク × 3 条件のコントラストを数え切って検査できるからです。
- 視覚回帰は判定と同じ環境で
- 基準画像は CI と同じ Linux で撮ります。手元の macOS で撮った基準は、色を差し替えても差分ゼロと判定していました。
- RSC 安全
- core の配布物が React を一切 import しないことを、ビルド後の成果物に対して検査します。Provider が無いのは設計であり、検査でもあります。
- 日本語入力
- 変換確定の Enter を送信と取り違えないことを、isComposing の観測点ごと検査します。観測点を間違えた検査は壊しても通るので、そこを固定しています。
- 見本のずれ
- トップの Modal 三連は静的な写しです。実物の Modal を開いて slot の並びを取り、写しと突き合わせる e2e が毎回走ります。
- AI の生成精度
- llms.txt だけを読ませたエージェントに全コンポーネントを書かせ、型エラーと禁止クラスがゼロであることを確かめます。落ちたら生成物ではなく文書を直します。
3. 色に名前と由来がある
色は「選ぶもの」ではなく「仕立てるもの」として設計しています。トーン(明度と彩度のレシピ)はモデルが所有し、色(色相と名前)はカラーウェイが持つ。 Raster は印刷インク、Tactile は織物の染料、Flatlay は文具。どのセットも 8 色の定番だけで、シーズナルドロップはしません。選んだ色には相方が組で付き、差し色を考えなくて済みます。
作っているのはアパレルを営む人間で、これはトーンイントーンとルックブックの道具立てをそのまま UI に持ち込んだものです。Lookbookでは染料の見本と、同じ一着を全色に着せた試着室を見られます。
4. 日本語で使う前提で作っている
IME の変換確定でフォームが送信される事故を、利用側が何もしなくても防ぎます。和文の見出しの改行、行長、数字の字形も、テーマが所有する値として持っています。英語圏のライブラリを日本語で使ったときに最初に当たる壁を、最初から無くしてあります。
あえてしないこと
- Provider を要求しない。 AI が設置を忘れて壊れる経路を最初から作らない
- アニメーションライブラリを入れない。 CSS だけで動かし、利用者のバンドルに乗せない
- Web フォントを配らない。 システムフォントで成立する書体設計にする
- テーマの共通実装を引き上げない。 一致率が上がっても「まだ差を作る必要が無かった」の意味しか持たない
- 9 色目を足さない。 検査で数え切れる範囲が、保証できる範囲
- 独自の props 名を作らない。 React Aria の慣習に従い、AI の事前知識で書けるようにする
向いていない場合
日付の入力(DatePicker)はまだありません。React Aria が挙動を持っているので次に足す予定です。表の列リサイズ・仮想スクロール・行内編集、Slider、ファイル添付も持っていません。今日それが要るなら別のライブラリが早いです。ドキュメントは日本語が一次で、バージョンは 0.x です。API は変わります。