コンテンツにスキップ

UIプリミティブ — フィールドガイド

モダンなアプリを眺めていて「あのパーツって何て呼ぶんだろう?」と思ったことがあるなら、このページはまさにあなたのためのものです。

あなたが使っているすべてのインターフェースは、UIプリミティブと呼ばれる、驚くほど少数の再利用可能な基本要素から構築されています。それぞれに名前があります。ちょっと変わった名前のこともあります。でも、一度そのメタファーに気づくと、もう見えないものには戻れません。

En Parlant~ は Mantine という React コンポーネントライブラリを使用しており、これらすべてがすぐに利用できます。では、フィールドガイドをどうぞ。


トーストは、画面の端からポップアップして表示される小さな通知で、数秒間留まったあとスライドして消えます。トースターからパンが飛び出すように——ただし重力が逆に働いて、いずれ中に戻っていきます。

En Parlant~ では、トーストは 右下隅 に表示されます(Mantine の @mantine/notifications を使用)。例えば:

  • 「データベースの読み込みに成功しました」 — ポップ
  • 「TTS音声が設定されていません」 — ポップ
  • 「Lichess への接続に失敗しました」 — ポップ、ちょっと悲しくなります

あなたが頼んだわけでもないのに、勝手に現れ、メッセージを届けて去っていきます。UI界の伝書鳩です。

カードは、ボーダーやシャドウを持つ長方形のコンテナで、関連するコンテンツをまとめてグループ化します。机の上に置かれたインデックスカードを想像してください——はっきりとした縁があり、ひとつのことを保持し、持ち上げて動かすことができます。

En Parlant~ では、以下のようなところでカードが使われています:

  • データベースブラウザのゲームプレビューGameCard)——プレイヤー名、結果、日付
  • 盤面ポジションエディタEditingCard)——カスタムポジションを設定するときにめくるカード
  • データベースページのデータベースエントリ——各データベースがグリッド内で独自のカードを持ちます

カードには Paper という近縁種がいます。基本的にはアートスクールに通ったカードです。同じ考え方——ボーダーやシャドウを持つコンテナ——ですが、意味的な役割は少なめです。Paper はただ「自分は表面です」と言っているだけです。分析パネルやデータベース情報表示の背景として登場します。

現時点では En Parlant~ では使われていませんが、知っておく価値はあります。ドロワーは画面の端からスライドして入ってくるパネルで、机の引き出しのようなものです。(以上です。メタファーはそれだけです。UIデザイナーがとても素直だった日だったのでしょう。)


モーダルは、あなたの注意を強制的に引きつけるポップアップダイアログです。背景をグレーアウトさせ、何か他のことをする前にまずこれに対処するよう求めます。UIパターン界の幼児です——「今すぐこっちを見て!」

En Parlant~ では、本当にあなたの集中が必要な場面でモーダルを使用しています:

  • 「すべてのデータを消去してもよろしいですか?」ClearDataModal)——どのデータを消し去るか選べるチェックボックス付き
  • 「アップデートが利用可能です」UpdateModal)——ダウンロード中のプログレスバー付き
  • 「ゲームをインポート」ImportModal)——PGNを貼り付け、FENを入力、またはリンクをドロップ
  • 「新しいレパートリーを作成」CreateRepertoireModal)——名前を付け、設定して、開始
  • 「En Parlant~ について」About)——バージョン情報、クレジット、おなじみのバックステージパス

モーダルはこう言います:「これは会話です。今、それをしています。」

ダイアログはモーダルの礼儀正しい従兄弟です。Mantine では基本的に同じコンポーネントですが、UIデザイン理論ではダイアログはより小さく、より焦点が絞られたもの——単一の質問と回答——です。「変更を保存しますか?」はい / いいえ。完了。

En Parlant~ では、保存されていない変更を破棄してよいか確認するような、素早いはい/いいえの場面で ConfirmModal を使用しています。


ツールチップは、何かにホバーすると表示される小さなラベルです。あなたが困った顔をしていると答えをそっとささやいてくれる、親切な見知らぬ人です。

ツールチップは En Parlant~ のあちこちにあります。ほぼすべてのアイコンボタンにホバーすると表示されます:

  • ↻ ボタンにホバー → 「リロード」
  • 切り詰められたファイルパスにホバー → フルパスが表示される
  • 注釈記号にホバー → その記号の意味が表示される
  • 分析パネルの手にホバー → ミニチュアの盤面プレビューがポップアップ

ツールチップは元祖「マニュアル不要」です。

ポップオーバーは、大学院に進学したツールチップです。テキストラベルを表示するだけでなく、ボタン、画像、小さなチェスボードなど何でも含めることができます。

En Parlant~ では、エンジン分析の手にホバーすると、ポップオーバーがそのポジションでの盤面プレビューを描画します。ツールチップですが、ビジュアル教材を持参しています。

メニューは、何かをクリック(または右クリック)すると表示されるアクションのリストです。コンピューティングの黎明期から使ってきたでしょう——ファイル、編集、表示。お馴染みのパターンです。

En Parlant~ には2つの種類があります:

  • トップバーメニュー — クラシックなファイル / 編集 / 表示のメニューバーで、Mantine の Menu コンポーネントで構築されています。右側にキーボードショートカットが表示されます。年金をもらえるほど歴史のあるデザインパターンです。
  • コンテキストメニュー — ゲームツリーの手を右クリックすると、変化の昇格、ここから削除、ラインのコピーなどのオプションが表示されます。mantine-contextmenu ライブラリを使用してさらに洗練されています。

メニューには独自のサブ用語があります:Menu.Target(クリックする対象)、Menu.Dropdown(表示されるリスト)、Menu.Item(各オプション)、Menu.Divider(「ここからセクションが変わります」を示す細い線)。


レイアウトの名コンビです。

  • Stack はものを縦に並べます——上に積み重ねていきます。本を積み上げるように。
  • Group はものを横に並べます——横並びに。チェスの駒を棚に並べるように。

それぞれ文字通り100以上のファイルに登場します。アプリ全体で最もよく使われるコンポーネントです。ものがきれいに配置されているときはいつでも、Stack か Group が仕事をしています。

Flex は Stack と Group の万能ナイフ的な従兄弟です。ものが折り返したり、伸びたり、縮んだり、反転したり、予想外の振る舞いをする必要があるとき、Flex が CSS Flexbox モデルのフルコントロールとともに登場します。

分析パネルの手順リストで使用されています——テキストのように折り返して流れていく手順のシーケンスがありますよね?あれは Flex が裏で頑張っています。

Box はシルクハットをかぶった <div> です。単体では何もしません——ただのジェネリックなコンテナです。しかし Mantine のスタイリングプロップを受け入れるため、「この要素を囲むものが必要」というときに非常に便利なラッパーになります。

Box は150以上のファイルに登場します。コンポーネントライブラリのガムテープです。

名前のとおりの動作をします。何かを中央に配置します。水平に。垂直に。両方。以上。

空の状態のときに登場します——アカウントが連携されていない、データベースが読み込まれていない、まだデータがない場合です。大きなアイコン、メッセージ、そして Center が完璧な位置にしてくれます。中央からずれた空の状態なんて誰も好きではありません。

シンプルなグリッドです。列数を指定すると、ウィンドウのリサイズに合わせてカードをきれいなグリッドに並べ替えてくれます。データベースページでは、レスポンシブグリッドにデータベースカードを配置するために使用されています。

コンテンツがオーバーフローしたときにスクロールするコンテナです。CSS の overflow: auto で無料で手に入りそうなもの——実際そうなのですが、ScrollArea はスタイル付きのスクロールバー、慣性スクロール、オーバーフロー検出を追加してくれます。ゲームツリーパネル、分析ライン、そしてコンテンツがボックスより高くなる可能性のあるすべての場所を包んでいます。

AppShell はマスターレイアウト——アプリケーション全体の骨格です。ヘッダーの位置、サイドバーの位置、メインコンテンツの位置を定義します。他のすべてがこの中にネストされます。

使うのは一度だけです。家の基礎です。

Portal は魔法のワームホールです。コンポーネントをDOMツリーの通常の位置の外側にレンダリングし、別の場所——通常はドキュメントのルート——に配置します。これが、ポップオーバーや盤面プレビューが overflow: hidden を持つ親コンテナにクリップされるのを防ぐ仕組みです。

Portal は見えません。その効果だけが見えます。UIコンポーネントの裏方スタッフです。


テキスト付きのクリックできる長方形です。これはご存知でしょう。Mantine では、ボタンにはバリアントがあります:

  • filled — 塗りつぶしの色、高い強調。「私をクリックして、私は重要です。」
  • outline — ボーダーだけ。「選択肢の一つですが、プレッシャーはありません。」
  • subtle — ほぼ存在感なし。「必要なときはここにいます。」
  • default — ニュートラルな中間地点。

En Parlant~ ではこれらすべてが150以上のファイルで使用されています。最もよく見るパターンは、モーダルの下部に並んだ Group のボタン——「キャンセル」(subtle)と「確認」(filled)です。定番です。

ActionIcon は、テキストラベルを手放してアイコンライフスタイルに全振りしたボタンです。コンパクトで正方形、その目的を伝えるためにアイコン(とツールチップ)に頼ります。

ツールバーボタン、パネルコントロール、閉じるボタン——すべて ActionIcon です。アクションを提供する最もスペース効率の良い方法です。

Switch は、小さな照明スイッチのように見えるトグルです。左にパチッ、右にパチッ。オン。オフ。

設定では、Switch が二択の選択を制御します:

  • サウンドのオン/オフ
  • TTSナレーションの有効/無効
  • ダークモード / ライトモード

物理的なメタファーが秀逸すぎて、おじいちゃんおばあちゃんでも理解できます。

Slider は、値を選択するためにハンドルを前後にドラッグするトラックです。平たくなった音量ノブのようなものです。

En Parlant~ ではスライダーを以下のように使用しています:

  • フォントサイズ — ドラッグして調整
  • 音量 — ドラッグして調整(もちろん)
  • CPUコア数 — エンジンに何コア使わせるか?
  • ハッシュメモリ — エンジンのハッシュテーブルにどれだけのRAMを使うか?

範囲を選択するための2つのハンドルを持つ RangeSlider もあります——レーティング範囲でゲームをフィルタリング(例:2000–2200)したり、期間でフィルタリングしたりするのに使われています。

一度にちょうど1つだけ選択されるボタンの行です。カーラジオのプリセットのように——1つ押すと、他のが戻ります。

以下の切り替えに使用されています:

  • 分析チャートでのセンチポーン評価と勝ち/引き分け/負けのパーセンテージの切り替え
  • 異なる棋譜表記フォーマット
  • エンジンのライン数

ご存知のものです。Checkbox は「該当するものをすべて選択」、Select ドロップダウンは「このリストから1つ選択」です。アプリ全体の設定、フィルタ、フォームに登場します。Clear Data モーダルには特に気持ちの良いチェックボックスのセットがあり、自分の破壊を自分で選べます

入力中に補完候補を提示するテキスト入力です。データベースブラウザのプレイヤー検索で使用されています——名前を入力し始めると、一致するプレイヤーが下に表示されます。

FileInput はクリックするとファイルピッカーを開きます——PGNファイルの読み込み用のインポートモーダルで使用されています。DateInput は日付選択用のカレンダーをポップアップ表示します——日付でゲームをフィルタリングするのに使用されています。精度を下げたい場合に使う MonthPickerInputYearPickerInput もあります(Lichess データベースの月別フィルタリング、Masters データベースの年別フィルタリング)。


何かがどこまで進んだかを示すために、左から右に満たされていく水平バーです。アプリのアップデート(ダウンロード進捗)で使用され、さらに——より創造的な使い方として——分析パネルでの勝ち/引き分け/負けの確率表示にも使われています。3つの色付きセクション(白、灰、黒)がバーを比例的に満たします。プログレスインジケータに偽装した小さな棒グラフです。

Loader は「作業中です、ちょっと待ってください」と伝える回転アニメーションです。データベースの読み込み中、プレイヤーの統計情報の取得中、またはその他の非同期処理の実行中に表示されます。

Skeleton は、まだ読み込まれていないコンテンツの形状を模した灰色のプレースホルダーです。空白の画面やスピナーの代わりに、カードやテキストがこれから表示される場所のゴーストアウトラインが見えます。ローディング状態の設計図です——「本物の家具は配送中です。」

データベースページでは、カードグリッドの読み込み中にスケルトンが使用されています。スピナーだけよりもはるかにエレガントです。

読み込み中のコンポーネントの上にかぶせる半透明のブランケットです。分析チャートで使用されています——オーバーレイの背後にチャートがまだ見えますが、暗くなっており、上にスピナーが表示されます。「まだここにいます、ただ更新中です。」


バッジは小さな色付きラベルです——カンファレンスの名札のようなものです。En Parlant~ では、SpeedBadge コンポーネントがバッジを使って、色分けされた持ち時間を表示します:

  • 🩷 ピンク — UltraBullet
  • 🔴 — Bullet
  • 🟠 オレンジ — Blitz
  • 🟢 — Rapid
  • 🔵 — Classical
  • 🟣 — Correspondence

各バッジは小さく、カラフルで、一目でゲームのスピードを伝えます。

keyboard の略です。あの特徴的な浮き上がったキーのスタイリングでキーボードキーを表示します。キーバインド設定で Ctrl + Z のようなものを表示するのに使用されます。キーボード上の実際の物理キーをCSSで再現したもので、嬉しくなるほどスキューモーフィックです。


区切ったり折りたたんだりするやつら

Section titled “区切ったり折りたたんだりするやつら”

セクションを区切る水平線です。それだけです。線です。しかしスタイル付きの線で、オプションで真ん中にテキストラベルを持つことができます——インポートモーダルの「PGNを貼り付け」と「FENを入力」を分ける「— OR —」のディバイダーのように。

30以上のファイルで Divider が使用されています。結局、区切りが必要な場面はたくさんあるのです。

Collapse は、スムーズなアニメーションで展開・収縮するセクションです。クリックで表示、クリックで非表示。データベースのフィルタオプションで使用されています——常にすべてのフィルタを表示する必要はないので、必要になるまで Collapse の裏に収まっています。


TipTap をベースにした、見たまま編集できるフルテキストエディタです。太字、斜体、リスト、なんでもありです。ゲームの注釈を書くのに使用されます——ある手がなぜ素晴らしかったか、あるいはなぜひどかったかを説明するためのコメンタリーノートです。

これは単一の細胞というよりも複合生物に近いプリミティブです。内部では TipTap + ProseMirror + Mantine のスタイリングです。しかしユーザーの視点からは、フォーマットが効くただのテキストボックスです。

@mantine/chartsRecharts をラップしたもの)の AreaChart が、評価グラフ——分析パネルの下部に沿って走る波形——を動かしています。中央線より上の白い領域は白が優勢、下の黒い領域は黒が優勢を意味します。

チャートの任意のポイントをクリックすると、その手にジャンプできます。インタラクティブなデータビジュアライゼーションとチェス分析の融合です。カスタムツールチップやゲームフェーズ(オープニング → ミドルゲーム → エンドゲーム)を示すリファレンスラインまであります。

mantine-datatable ライブラリによるもので、ソート、ページネーション、行選択、フィルタリングを備えたフル機能のデータテーブルです。データベースブラウザのゲームリスト、プレイヤーリスト、トーナメントリストを支えています。自分がチェスアプリの中にいることを分かっているスプレッドシートです。


一部のプリミティブはそれ自体では何も表示しませんが、他のすべてを機能させています:

  • MantineProvider — アプリ全体をラップし、テーマ(色、ダークモード、コンポーネントのデフォルト値)を提供します
  • Portal — レンダリングされたコンテンツをDOMの別の場所にテレポートします
  • useHotkeys — キーボードショートカットを接続するフック(コンポーネントではありません)
  • useForm — フォームの状態、バリデーション、エラーハンドリングを管理します
  • useDebouncedValue — 入力が止まるのを待ってから検索を実行します。礼儀正しいフックです。

参考として、En Parlant~ で使用されているすべてのプリミティブファミリーを、機能別にグループ化して掲載します:

カテゴリプリミティブ
レイアウトAppShell, Box, Center, Flex, Group, Stack, SimpleGrid, ScrollArea, Portal
サーフェスCard, Paper
オーバーレイModal, Tooltip, Popover, Menu, ContextMenu, LoadingOverlay
通知Toast (@mantine/notifications 経由)
ボタンButton, ActionIcon, CloseButton, ThemeIcon
入力TextInput, Textarea, NumberInput, Select, Autocomplete, Checkbox, Switch, Slider, RangeSlider, SegmentedControl, FileInput, DateInput, MonthPickerInput, YearPickerInput
データ表示Table, DataTable, Badge, Code, Kbd, Rating, Image
タイポグラフィText, Title, Anchor
進捗Progress, Loader, Skeleton
構造Divider, Collapse
リッチコンテンツRichTextEditor (TipTap), AreaChart (Recharts)
テーマMantineProvider, createTheme, useColorScheme
フックuseForm, useHotkeys, useToggle, useDebouncedValue, useClickOutside, useElementSize

すべて Mantine v8 とそのエコシステムパッケージ(@mantine/core@mantine/notifications@mantine/dates@mantine/charts@mantine/form@mantine/tiptapmantine-datatablemantine-contextmenu)から提供されています。


次に画面の隅から小さなメッセージがスライドしてくるのを見たら——それはトーストです。ゲームプレビューを囲む長方形——それはカードです。コンテンツが読み込まれる前にちらつく灰色の塊——それはスケルトンです。

名前を覚えると、どこでも見えるようになります。あらゆるアプリ。あらゆるウェブサイト。同じ数十個のプリミティブが、千通りの異なる方法で組み合わされています。

どこまでいってもレゴブロックなのです。