ヘッドレスコンポーネントシステム · 新しいリソース

Ariakit デザインシステム.

Ariakitは、共有状態が明示された、スタイルを持たないReactコンポーネントと、組み合わせて使えるアクセシブルなパーツを提供します。コンボボックスでは、入力中のテキストと確定済みの選択項目が分かれているため、検索ベースの選択UIに適しています。以下のリファレンス検索では、グループ化された結果や利用不可の結果を使って、この違いを示します。

OpenDesign ガイド9 章リファレンス項目29件オリジナルアプリケーションガイド
01

Ariakit デザインシステム インターフェースのプレビュー

グループ化されたリファレンスを絞り込み、下矢印キーとEnterキーで選択して、結果を確認し、ローカルの閲覧リストに追加します。

アクセシブルなリファレンス検索完全な例を開く
ネイティブの@ariakit/react 0.4.40とReact 19。ビジュアルトークンとサンプルのリファレンス内容はすべてオリジナルです。· 実装リファレンス
02

Ariakit デザインシステム デザインリファレンス

Ariakit React 0.4.40は、スタイルを持たないアクセシビリティツールキットです。以下のページの配色、フォントスケール、スペーシングを、ネイティブのデザインテーマとして公開するものではありません。すべての--app-*値は、この実行可能なサンプルで使用するために明示的に設定したオリジナルの構成です。コンポーネント名と状態属性はAriakit APIです。

オリジナルのセマンティックカラー設定

ソース
名前 / ルール値 / 設定用途
--app-canvas#f5f3ee ページの背景。
--app-surface#fffコンボボックスのポップオーバーとリファレンスカード。
--app-text#292e29 本文の主要テキスト。
--app-muted#657064 補助ラベルとヒント。
--app-border#d8ddd4 入力欄とカードの境界線。
--app-action#285f48 主要アクションとフォーカスリング。
--app-on-action#fff主要アクション上のテキスト。
--app-active#e3eee4 アクティブな選択肢と選択済みアクションの背景。

元の形状と間隔

ソース
名前 / ルール値 / 設定用途
--app-radius10px入力欄、ポップオーバー、参照カードの角丸。
--app-space-18px定義済みの元の間隔スケール。
--app-space-216px定義済みの元の間隔スケール。
--app-space-324px定義済みの元の間隔スケール。
--app-space-432px定義済みの元の間隔スケール。
Combobox padding13px 48px 13px 14px開閉コントロール用のスペースを確保。
Popover maximum height340px結果が多い場合はリスト内をスクロール。
Popover gutter8px入力欄と候補の間隔を決める実際のgutter prop。

元のタイポグラフィ

ソース
名前 / ルール値 / 設定用途
Font familysystem-ui, sans-serifフォントのダウンロードや、Ariakit専用フォントは不要です。
Page heading36px / 1.1; 30px mobile元のページ階層。
Input text15px元のコンボボックスの文字サイズ。
Option text14px元の結果ラベルの文字サイズ。
Group label11px, uppercase, 700元の視覚的なグループ分けのスタイル。
Supporting hint12px / 1.7キーボード操作の案内のリズム。

ネイティブな構成と状態

ソース
名前 / ルール値 / 設定用途
ComboboxProvider.inputValueControlled query string現在の0.4.40の入力状態はAPI。setInputValueでフィルタリングを更新します。
ComboboxProvider.selectedValueControlled reference name確定済みの選択は検索語とは独立しています。
ComboboxGroup / ComboboxGroupLabelFoundations / Componentsラベル付きのネイティブな選択肢グループ。
ComboboxPopover.sameWidthtrueアンカーの幅に追従します。
ComboboxItem.disabledtrue for Experimental grid利用不可の項目は選択できません。
[data-active-item]CSS state selectorキーボードでアクティブな選択肢を、選択済みの項目とは独立してスタイル設定します。
Combobox autoSelectNot enabled in this specimen下矢印キーでリストに移動し、Enterキーで選択肢を選びます。
03

Ariakit デザインシステム完全ガイド

実際のインターフェースで、このデザインシステムを選び、適用し、レビューするための実践ガイドです。

DESIGN-ariakit.md

詳しいガイダンス、実装の出発点、ソースへのリンクをまとめています。

ガイドをダウンロード

Ariakit デザインシステム:コンボボックスの状態モデルから始める

まずコンボボックスの状態モデルを確認する

AriakitのComboboxProviderは、ラベル、編集可能な入力欄、開閉ボタン、ポップアップ、選択肢を連携させます。プロバイダーが共通の操作状態を管理し、各コンポーネントがそれぞれの構造を担います。これにより、キー入力のたびに新たな選択として扱うことなく、検索欄と選択項目の詳細パネルを独立して配置できます。

この OpenDesign ガイドから

この参照項目検索の例では、2つの名前付きグループに分けた6件の項目を表示します。フィルタリングはアプリケーション側のコレクションが担い、移動と選択肢の選択はネイティブのコンボボックスが担います。この境界を明確にしておくと、静的な項目を別のデータソースに置き換える際にも便利です。フィルタリング後の結果と、現在確定済みの項目は必ずしも同じではありません。

関連する仕様を確認する

Ariakit デザインシステム:検索テキストと確定済みの選択は別の状態

検索テキストと確定済みの選択項目は別の状態

この例では、入力中のテキストをinputValueとsetInputValueで管理し、選択した参照項目をselectedValueとsetSelectedValueで管理します。検証済みの0.4.40版APIでは、inputValueが入力状態を表す現在の名前です。古い例では、非推奨のvalue/setValueエイリアスが使われている場合があります。完全なコードでは現在の名前を使用しています。

「色」と入力すると候補が絞り込まれますが、表示中の詳細カードはすぐには切り替わりません。「色の役割」を選択すると、その項目が確定され、パネルが更新されます。検索をクリアしても、最後に選択した参照項目は保持されます。入力途中の検索語をすべて確定値として扱うと、詳細ビューが無効な項目や存在しない項目に切り替わってしまいます。

関連する仕様を確認する

Ariakit デザインシステム:ラベル、入力欄、開閉ボタン、ポップオーバーを連携させる

ラベル、入力欄、開閉ボタン、ポップオーバーを連携させる

ComboboxProviderは、共通の状態をComboboxLabel、Combobox、ComboboxDisclosure、ComboboxPopoverに提供します。画面に表示されるラベルは入力欄の内容を示します。開閉ボタンは明示的なアクセシブルネームを持つ独立したボタンです。ポップオーバーではsameWidthと8ピクセルのgutterを指定し、アンカーとの位置をそろえています。

各結果は、固定されたvalueを持つComboboxItemです。「トークン」と「コンポーネント」は、ComboboxGroupLabelの見出しを持つネイティブのComboboxGroupセクションです。構造化されていないリストに太字の見出しを挿入するだけでは、同じグループ関係を表現できません。ネイティブな構成要素を使うことで、キーボード操作のモデルとともにその関係も示せます。

関連する仕様を確認する

Ariakit デザインシステム:ネイティブ項目を表示する前にデータをフィルタリングする

ネイティブ項目を描画する前にデータを絞り込む

サンプルのコレクションには、利用可能な参照項目が5件と、意図的に利用不可にした「実験的なグリッド」が1件含まれています。フィルタリングでは、各参照項目の名前に対する大文字・小文字を区別しない部分一致検索をアプリケーション側で行います。結果を含む場合にのみ2つのグループを表示し、結果の間に空の見出しが残らないようにします。

検索結果が0件の場合は、検索をクリアするか「色」で検索するよう促す専用メッセージを表示します。このメッセージは選択可能な項目にはしません。利用不可の項目は該当する場合も表示され、「利用不可」というラベルが付きます。また、ネイティブのdisabled propにより、確定済みの選択項目になるのを防ぎます。

関連する仕様を確認する

Ariakit デザインシステム:下矢印キーからEnterキーまでの実際の操作を確認する

実際の下矢印キーからEnterキーまでの操作を確認する

この例ではautoSelectをオフにしています。検索語を入力した後、下矢印キーで候補リストに移動し、Enterキーでアクティブな項目を選択します。Escapeキーでポップオーバーを閉じます。表示される操作案内と一致しており、ドロップダウンが表示されるかどうかだけでなく、選択後の詳細タイトルも確認済みです。

別の製品では自動ハイライトが適切な場合もありますが、矢印キーによる移動の開始位置が変わります。すでに1件の結果がアクティブな状態では、下矢印キーをもう一度押すと、フォーカスが入力欄に戻ることがあります。この例ではその不一致を避け、data-active-itemでアクティブな項目をスタイル設定することで、キーボード上の位置と、閲覧リストへの保存状態を区別しています。

  1. 「色」と入力し、一致する選択肢が表示されるまで待ちます。
  2. 下矢印キーを押してからEnterキーを押し、「色の役割」の詳細パネルを確認します。
  3. 利用不可または存在しない参照項目を検索し、意図しない選択が確定されないことを確認します。

関連する仕様を確認する

Ariakit デザインシステム:アクティブな項目、フォーカスリング、保存状態にはそれぞれ異なる手掛かりを用いる

アクティブな選択肢、フォーカスリング、保存状態にはそれぞれ異なる手がかりがある

入力欄と開閉ボタンには、視認できるフォーカスアウトラインを表示します。アクティブな項目には、ネイティブのdata-active-item属性を使って、淡い緑色の背景と内側の1ピクセルのアウトラインを適用します。無効な項目は強調を抑え、明示的なテキストラベルを残します。これらのスタイルはホバーだけに依存しません。

選択した参照項目がすでに閲覧リストにある場合、Addボタンは無効になり、テキストも変わります。この保存状態はアプリケーション側のものであり、コンボボックスで現在アクティブな結果とは別の状態です。淡い緑色の背景を使うことで、無効なアクションが有効な主要ボタンのように見えるのを避けています。

関連する仕様を確認する

Ariakit デザインシステム:閲覧リストを追加しても、現在の参照項目は切り替わらない

閲覧リストは現在のリファレンスの代わりにはならない

参照項目を追加すると、その名前がローカル配列に1回だけ追加されます。現在の参照項目は表示したままなので、ユーザーはそのメモを確認できます。閲覧リストの各行には、項目名を明示したRemoveボタンがあります。項目を削除すると、その参照項目が選択中であればAddボタンが再び有効になります。件数は配列の長さから算出します。

サンプルの詳細コンテンツには、ファインダーを使って調べやすくするためのタイポグラフィ、スペーシング、コンポーネントに関するガイドが含まれています。値には、オリジナルのサンプルコンテンツであることが明記されています。「Display 36px」という値を含むType scaleレコードを、Ariakitのタイポグラフィトークンだと読者が誤解しないようにしてください。Ariakitはこのデザイン言語を提供していません。

関連する仕様を確認する

Ariakit デザインシステム:ページ全体のサイズを変えずにポップオーバーの領域を確保する

ページ全体のサイズを変えずにポップオーバーの領域を確保する

ポップオーバーの幅は入力欄に合わせ、高さは340pxに制限します。結果が多い場合はその領域内をスクロールでき、選択した詳細カードは通常のドキュメントコンテンツとして表示されます。詳細カードを別のカラムに移動しても、入力欄、開閉ボタン、選択肢のポップアップの関連付けを保ってください。項目を確定すると、同じ選択レコードが更新される必要があります。

元の700pxのブレークポイントでは、ファインダーと詳細カードが縦に並びます。検索コントロール、キーボード操作のヒント、読書リストは、ドキュメント上で選択カードより前に配置されます。装飾用の参考画像は、タイトルと注記が実際の意味を伝えるため、支援技術には読み上げられないようにします。

  • 項目間の読みやすい間隔を保ちながら、長い選択肢リストをその領域内でスクロールできるようにします。
  • 確定した詳細パネルは、一時的なポップオーバーの外に配置します。
  • モバイルでも入力欄のラベルとキーボード操作のヒントを表示します。

関連する仕様を確認する

Ariakit デザインシステム:プロバイダー、コレクション、スタイルシートを接続する

プロバイダー、コレクション、スタイルシートを接続する

Reactプロジェクトに@ariakit/react 0.4.40をインストールし、App.jsxにあるプロバイダーとコンポーネントの構成をすべて維持してください。現在の例では、inputValue/setInputValueとselectedValue/setSelectedValueをそれぞれ別の制御ペアとして使用しています。現在の入力クエリによってポップアップから除外されても、選択レコードを利用できる状態にしてください。

提供されたstyle.cssをコンポーネントとともにインポートしてください。data-active-itemルールはコンボボックスのキーボード上の位置に連動し、保存済みリストのスタイルはアプリケーションの状態に連動します。非同期で読み込む結果に差し替える場合も、この2つの状態の流れとグループ/選択肢の関係を維持してください。確定した詳細パネルを、入力途中のクエリ文字列で置き換えないでください。

関連する仕様を確認する

Ariakit デザインシステムのコンポーネント例

制御機能をすべて備えたリファレンスファインダー

プロバイダー、ラベル、入力欄、開閉ボタン、グループ化されたポップオーバー項目、読書リストのローカル操作。

jsx
import React,{useState} from 'react';
import * as Ariakit from '@ariakit/react';
const resources=[{name:'Type scale',group:'Foundations',code:'Aa',description:'A compact editorial hierarchy for headings, supporting text and labels.',notes:['Display · 36px / 1.1','Section · 24px / 1.25','Body · 16px / 1.6'],color:'#f0dbc3'},{name:'Color roles',group:'Foundations',code:'◐',description:'Separate surface, text, boundary and action roles before naming brand colors.',notes:['Canvas and raised surface','Primary and muted text','Action and on-action pair'],color:'#d6e5d8'},{name:'Spacing rhythm',group:'Foundations',code:'▥',description:'Use a small set of intervals to show relationships between content groups.',notes:['8px within a compact group','16px between related controls','32px between sections'],color:'#d6dfee'},{name:'Form field',group:'Components',code:'⌑',description:'Keep the label, hint, input and error message in one understandable group.',notes:['Persistent visible label','Hint before an error exists','Error connected to the input'],color:'#e9d8de'},{name:'Navigation menu',group:'Components',code:'☷',description:'A small set of destinations with a visible current location and keyboard access.',notes:['Destination labels describe content','Current item has a text/state cue','Collapsed layout keeps names'],color:'#e7e0c5'},{name:'Experimental grid',group:'Components',code:'▦',description:'Unavailable in this sample collection.',notes:[],color:'#e3e3e3',disabled:true}];
export default function App(){const[query,setQuery]=useState(''),[chosen,setChosen]=useState('Type scale'),[saved,setSaved]=useState([]);const selected=resources.find(x=>x.name===chosen)||resources[0],matches=resources.filter(x=>x.name.toLowerCase().includes(query.toLowerCase()));return <main className="resource-finder"><header><p className="eyebrow">ARIAKIT · ACCESSIBLE PRIMITIVES</p><h1>A reference, within reach.</h1><p>Search a small collection with the keyboard, inspect the result and keep a local reading list.</p></header><div className="finder-grid"><section className="search-area"><Ariakit.ComboboxProvider inputValue={query} setInputValue={setQuery} selectedValue={chosen} setSelectedValue={setChosen}><Ariakit.ComboboxLabel className="label">Find a reference</Ariakit.ComboboxLabel><div className="input-row"><Ariakit.Combobox className="combobox" placeholder="Try type, color or form" /><Ariakit.ComboboxDisclosure className="disclosure" aria-label="Show reference suggestions">⌄</Ariakit.ComboboxDisclosure></div><Ariakit.ComboboxPopover gutter={8} sameWidth className="popover">{['Foundations','Components'].map(group=>{const items=matches.filter(x=>x.group===group);return items.length?<Ariakit.ComboboxGroup key={group}><Ariakit.ComboboxGroupLabel className="group-label">{group}</Ariakit.ComboboxGroupLabel>{items.map(x=><Ariakit.ComboboxItem key={x.name} value={x.name} disabled={x.disabled} className="combo-item"><span>{x.name}</span><small>{x.disabled?'Unavailable':x.group==='Foundations'?'Guide':'Pattern'}</small></Ariakit.ComboboxItem>)}</Ariakit.ComboboxGroup>:null})}{!matches.length&&<p className="empty" role="status">No matching reference. Try “color” or clear the search.</p>}</Ariakit.ComboboxPopover></Ariakit.ComboboxProvider><p className="hint">Type to filter. Use ↓ and ↑ to browse, Enter to choose, Escape to close.</p><div className="collection-note"><span>06</span><div><strong>Sample references</strong><p>Five available, one deliberately disabled to show an unavailable item.</p></div></div><section className="reading-list"><h2>Your reading list <small>{saved.length}</small></h2>{saved.length?<ul>{saved.map(name=><li key={name}><span>{name}</span><Ariakit.Button className="remove" onClick={()=>setSaved(saved.filter(x=>x!==name))} aria-label={`Remove ${name}`}>Remove</Ariakit.Button></li>)}</ul>:<p className="muted">Choose a reference, then add it here.</p>}<p className="local-note">This list stays in memory and clears on reload.</p></section></section><section className="reference-card" aria-label="Selected reference"><div className="reference-art" style={{background:selected.color}} aria-hidden="true"><span>{selected.code}</span><i></i></div><div className="reference-body"><p className="eyebrow">{selected.group} · SAMPLE CONTENT</p><h2>{selected.name}</h2><p>{selected.description}</p><ul className="note-list">{selected.notes.map(note=><li key={note}>{note}</li>)}</ul><Ariakit.Button className="primary" disabled={saved.includes(selected.name)} onClick={()=>setSaved([...saved,selected.name])}>{saved.includes(selected.name)?'Added to reading list':'Add to reading list'}</Ariakit.Button><p className="scope-note">These sample reference values are original content, not Ariakit design tokens.</p></div></section></div><p className="selection-status" role="status">Selected reference: {selected.name}</p></main>}

コードリファレンス

  • inputValueは検索文字列、selectedValueは確定したリファレンスです。
  • 無効な項目も、検索クエリに一致すれば表示されます。
  • オリジナルのサンプルにあるタイポグラフィとスペーシングの値は、Ariakitの既定値ではありません。

オリジナルのビジュアル設定一式

セマンティックなアプリケーション変数、フォーカスリング、アクティブな選択肢のスタイル、レスポンシブレイアウト。

CSS
:root{--app-canvas:#f5f3ee;--app-surface:#fff;--app-text:#292e29;--app-muted:#657064;--app-border:#d8ddd4;--app-action:#285f48;--app-on-action:#fff;--app-active:#e3eee4;--app-radius:10px;--app-space-1:8px;--app-space-2:16px;--app-space-3:24px;--app-space-4:32px;font-family:system-ui,sans-serif}*{box-sizing:border-box}body{margin:0;background:var(--app-canvas);color:var(--app-text)}button,input{font:inherit}.resource-finder{max-width:1080px;padding:32px;margin:auto}.eyebrow{font-size:11px;font-weight:700;letter-spacing:.13em;color:var(--app-muted)}h1{font-size:36px;line-height:1.1;margin:16px 0}header>p:last-child{font-size:15px;line-height:1.7;max-width:620px;color:var(--app-muted)}.finder-grid{display:grid;grid-template-columns:1fr 1.1fr;gap:40px;margin-top:32px}.label{display:block;font-size:14px;font-weight:650;margin-bottom:10px}.input-row{position:relative;display:flex}.combobox{width:100%;padding:13px 48px 13px 14px;border:1px solid var(--app-border);border-radius:var(--app-radius);background:var(--app-surface);color:var(--app-text);font-size:15px}.disclosure{position:absolute;right:4px;top:4px;bottom:4px;width:36px;border:0;background:transparent;border-radius:6px;cursor:pointer}.combobox:focus,.disclosure:focus-visible,button:focus-visible{outline:3px solid var(--app-action);outline-offset:3px}.popover{z-index:50;max-height:340px;overflow:auto;background:var(--app-surface);border:1px solid var(--app-border);border-radius:var(--app-radius);box-shadow:0 8px 28px #243c2420;padding:8px}.group-label{font-size:11px;letter-spacing:.06em;text-transform:uppercase;font-weight:700;color:var(--app-muted);padding:10px}.combo-item{display:flex;justify-content:space-between;gap:16px;align-items:center;padding:12px 10px;border-radius:6px;cursor:default;font-size:14px;scroll-margin:8px}.combo-item small{font-size:11px;color:var(--app-muted)}.combo-item[data-active-item]{background:var(--app-active);outline:1px solid var(--app-action);outline-offset:-1px}.combo-item[aria-disabled=true]{opacity:.45}.empty{padding:12px;font-size:14px;line-height:1.6}.hint{font-size:12px;line-height:1.7;color:var(--app-muted);margin-top:12px}.collection-note{display:flex;gap:16px;align-items:flex-start;border-block:1px solid var(--app-border);padding:24px 0;margin:28px 0}.collection-note>span{font-size:40px;line-height:1;color:var(--app-action)}.collection-note strong{font-size:14px}.collection-note p{font-size:13px;line-height:1.6;color:var(--app-muted);margin:8px 0 0}.reading-list h2{font-size:17px;display:flex;justify-content:space-between}.reading-list h2 small{background:var(--app-active);border-radius:30px;padding:3px 8px}.reading-list ul{padding:0;list-style:none}.reading-list li{display:flex;justify-content:space-between;gap:12px;padding:12px 0;border-bottom:1px solid var(--app-border);font-size:14px}.remove{background:none;border:0;text-decoration:underline;color:var(--app-action);font-size:12px;cursor:pointer}.muted,.local-note,.scope-note{color:var(--app-muted);font-size:12px;line-height:1.7}.reference-card{border:1px solid var(--app-border);border-radius:var(--app-radius);overflow:hidden;background:var(--app-surface)}.reference-art{height:160px;position:relative;display:flex;align-items:center;justify-content:center;overflow:hidden}.reference-art span{font-size:96px;font-family:Georgia,serif;line-height:1;position:relative;z-index:1}.reference-art i{position:absolute;width:190px;height:190px;border:1px solid currentColor;opacity:.2;border-radius:50%;left:50%;top:35%}.reference-body{padding:24px}.reference-body h2{font-size:28px;margin:12px 0}.reference-body>p{line-height:1.65;font-size:14px}.note-list{list-style:none;padding:0;margin:24px 0}.note-list li{padding:10px 0;border-bottom:1px solid var(--app-border);font-size:13px}.primary{padding:12px 18px;border:1px solid var(--app-action);background:var(--app-action);color:var(--app-on-action);border-radius:6px;cursor:pointer;font-weight:600;font-size:14px}.primary:disabled{background:var(--app-active);color:var(--app-action);cursor:default}.scope-note{margin-top:16px}.selection-status{font-size:12px;color:var(--app-muted);margin-top:24px}@media(max-width:700px){.resource-finder{padding:24px 16px}h1{font-size:30px}.finder-grid{grid-template-columns:1fr;gap:28px}.reference-art{height:135px}}

コードリファレンス

  • Ariakitが提供するのは動作とセマンティクスであり、この配色やスペーシングのシステムではありません。
  • アクティブな結果はdata-active-itemを使ってスタイル設定します。
  • ポップオーバーには、独自の最大高とスクロール領域があります。
04

Ariakit デザインシステム:エージェントのセットアップ

実装の出発点

@ariakit/react 0.4.40およびReact 19で検証済みです。現在のinputValue/setInputValueの名前と、制御されたselectedValueを使用します。

jsx
// Create the project first:
// npm create vite@latest ariakit-specimen -- --template react
// cd ariakit-specimen && npm install
// In a Vite React project:
// npm install @ariakit/[email protected] react@19 react-dom@19
// Save the complete component as App.jsx and the visual configuration as style.css.
import React from 'react';
import {createRoot} from 'react-dom/client';
import App from './App.jsx';
import './style.css';
createRoot(document.getElementById('root')).render(<App />);
// index.html contains <div id="root"></div>.
// No Ariakit theme stylesheet is required; style.css is this example's original theme.
// Keep the template index.html and replace its entry with the code above.
// npm run dev

あなたのプロジェクト向けプロンプト

AI エージェント用プロンプト
提供されたAriakit 0.4.40のリファレンスファインダーをReactで使用します。ComboboxProviderのinputValue/setInputValueとselectedValue/setSelectedValueを独立させ、ネイティブのラベル付きグループと無効状態のExperimentalグリッド項目を維持し、項目を描画する前にデータを絞り込んでください。autoSelectをオフにした状態で、Downキーの後にEnterキーを押す検証済みの操作手順を維持し、data-active-itemのスタイルを保存済み状態とは別に設定します。確定したリファレンスを重複のないローカル読書リストに追加し、現在の詳細を破棄せずに削除できるようにしてください。オリジナルのスタイルシートもすべて含めます。
05

Ariakit デザインシステム:参照元と適用範囲

Ariakit React 0.4.40。すべてのビジュアルトークン、アートワーク、サンプルのリファレンス値はオリジナルの設定であり、Ariakitの公式パレットやタイポグラフィスケールを示すものではありません。読書リストの状態はローカルに保持されます。