Novi UI

なぜ 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 は変わります。

はじめる