設定
CursorやClaudeのように構成した、AIプロダクト向けの設定です。検索、グループ、外部リンクを備えた塗りつぶしのサイドバー、控えめなピッカーと入れ子のオプションを持つ行のカード、変更があったときだけ浮かび上がる暗い保存アイランド、⌘Sでの保存、チェックやサーバーからのフィールドエラー、コンテンツの形に合わせた読み込み状態を備えています。
Cursor、Claude、Codexはどれも同じ設定ページに落ち着きました。検索といくつかのグループ化されたセクションを持つ塗りつぶしのサイドバーと、右側にある、左にラベルと説明、右に控えめなコントロールを置いた行のカードです。Settingsはそのページです。セクションを保持し、どの設定ページでもうまくいかない点を処理します。編集内容の消失、二重保存、デスクトップのサイドバーからスマートフォンのリストへの切り替えです。
行には任意のコントロールを置けます。SettingsSelectはそれらのアプリが使うコンパクトな値のピッカーで、選択肢のメニューを開く小さなアウトラインのボタンです。SettingsNumberは押し続けると繰り返されるステッパーです。どちらも行にちなんだ名前が付くため、スクリーンリーダーは「Chat font, Serif」と読み上げます。SettingsLinkは別の何かを開く行で、アプリを離れるリンクにはシェブロンまたは矢印が付きます。SettingsNestedは、Run codeの下のネットワークアクセスのように、スイッチの下に依存オプションをスライドして開きます。Searchはラベル、説明、キーワードでサイドバーを絞り込み、Enterで最初の一致を開きます。SettingsChoiceは選択肢を画像カードにするため、見た目でテーマや密度を選べます。
指示するまで何も保存されません。値が保存済みのものと異なった時点で、DiscardとSaveを備えた暗いアイランドが下から浮かび上がり、サイドバーのそのセクションの項目にドットが付きます。元に戻すとバーは消えます。別のセクションを開こうとしたり、スマートフォンで戻ったり、タブを閉じようとしたりすると、切り替えはブロックされます。バーが揺れて先に保存または破棄するよう伝え、ブラウザーはタブを閉じる前に確認します。⌘SまたはCtrl+Sで、どこからでも保存できます。
保存すると、ボタンに進捗が表示され、その後アイランドが縮んでSavedのチェックになり、スライドして消えます。チェックに失敗した場合は、フィールドにエラーが表示され、フォーカスが最初のフィールドに移り、バーが修正すべき数を伝えます。サーバーが拒否した場合は、フィールドのエラーを返すかエラーを投げると、下書きは入力したままの状態で残ります。保存中に入力を続けると、新しい編集のためにバーは表示されたままになります。
スマートフォンでは、サイドバーが説明とシェブロンを持つグループ化されたリストになります。セクションをタップすると、戻るボタンとともにリストの上にスライドインし、フォーカスが見出しに移ります。セクションのデータを読み込む間は、スイッチの行の形をしたスケルトン、またはskeletonプロップで渡した独自のものが表示され、読み込みに失敗した場合はTry again付きのエラーが表示されます。
Proレジストリをcomponents.jsonに追加する
components.json トークンを追加する
アカウントページでトークンを作成し、
.env.localにHEXTAUI_PRO_TOKENとして設定してください。ブロックを追加する
pnpm dlx shadcn@latest add @hextaui-pro/settings
セクションをAPIに接続する
useSettingsFormは、渡した値の下書きを保持します。フィールドの下にエラーを表示するにはonSaveからフィールドエラーを返し、保存バーにメッセージを表示するにはエラーを投げます。どちらの場合も下書きは保持されます。
セクションごとに1つのルート
valueとonValueChangeでアクティブなセクションを制御すると、各セクションに専用のURLを持たせられます。未保存の変更がある間はシェルが切り替えをブロックするため、onValueChangeは離れても安全なときにだけ呼ばれます。
読み込みとエラー
セクションのデータを読み込む間、statusを渡します。スケルトンは150ms待つため、高速な読み込みでちらつくことはなく、エラー状態はonRetryを通じてTry againを提示します。
構造
外側から内側へ組み合わせるパーツ。
| パーツ | 説明 |
|---|---|
SettingsShell | ページ。セクションのナビゲーション、コンテンツ列、保存バー、未保存の変更を残して離れることに対するガード。 |
SettingsSection | 1つのセクション。開いている間だけ描画され、見出し、任意のアクション、読み込みとエラーの状態を備えます。 |
SettingsGroup | タイトルつきの行のカード。グループに関するメモを書く任意のフッターがあります。 |
SettingsRow | スクリーンリーダー向けに連携されたラベル、説明、コントロールと、その下のフィールドエラー。 |
SettingsSelect | 短いリストから1つの値を選ぶ、控えめなピッカー。 |
SettingsLink | ページ、ダイアログ、外部リンクを開く行。 |
SettingsNested | 親のスイッチがオンの間、スライドして開く依存オプション。 |
SettingsNumber | 押し続けると繰り返される−と+を備えた数値ステッパーで、Base UIのNumber Fieldの上に作られています。 |
SettingsChoice | テーマや密度のような、1つのオプションを選ぶための画像カード。radioのセマンティクスを持ちます。 |
SettingsSkeleton | 読み込み中のプレースホルダー。グループごとの行数とコントロールの形を設定できます。 |
useSettingsForm | 1つのセクションの下書き。変更を追跡し、検証し、保存し、セクションを保存バーに接続します。 |
useSettingsNavigate | コンテンツ内からセクションを開きます。サイドバーと同様に保護されています。 |
SettingsShell
すべてのdivプロップも受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
sections{ id, label, description?, icon?, group?, keywords?, href? }。同じgroupを持つ連続した項目は、見出しを共有します。keywordsは検索でセクションを見つけやすくし、hrefはその項目を外部リンクにします。 | SettingsSectionItem[] | – |
value制御する場合に開いているセクション。 | string | – |
defaultValue最初に開いているセクション。 | string | first section |
onValueChange別のセクションが開かれたときに呼ばれます。未保存の変更がある間や保存中は呼ばれません。 | (value: string) => void | – |
titleナビゲーションの上のページ見出しと、スマートフォンでの戻るボタンのラベル。 | ReactNode | "Settings" |
descriptionタイトルの下の行。 | ReactNode | – |
navHeaderサイドバーの上部にあるコンテンツ。アプリへのBackリンクなど。 | ReactNode | – |
searchableセクションの上に検索フィールドを追加します。 | boolean | false |
navFooterサイドバーの下部に固定されるコンテンツ。サインイン中のユーザーなど。 | ReactNode | – |
groupLabels各グループの名前をその上に表示します。オフにすると、グループは余白だけで区切られます。名前は引き続きスクリーンリーダー向けにグループのラベルとして使われます。 | boolean | true |
SettingsSection
すべてのsectionプロップも受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
idsections内のidと一致させます。 | string | – |
title見出し。 | ReactNode | the section's label |
description見出しの下の行。 | ReactNode | the section's description |
actions見出しの横のボタン。 | ReactNode | – |
status子要素の代わりに、スケルトンまたはエラーを表示します。 | "ready" | "loading" | "error" | "ready" |
skeletonstatusがloadingの間に表示する内容。 | ReactNode | <SettingsSkeleton /> |
errorエラー状態のメッセージ。 | ReactNode | – |
onRetryエラー状態にTry againを追加します。 | () => void | – |
| プロパティ | 型 | デフォルト |
|---|---|---|
titleカードの上の見出し。 | ReactNode | – |
description見出しの下にある、グループの内容を説明する控えめな行。 | ReactNode | – |
footerカードの下部にある、変更の影響などのメモを書く控えめな帯。 | ReactNode | – |
| プロパティ | 型 | デフォルト |
|---|---|---|
label行の内側のコントロールにラベルを付けます。 | ReactNode | – |
descriptionコントロールとともに読み上げられるヘルプテキスト。 | ReactNode | – |
errorコントロールを無効な値としてマークし、行の下にメッセージを表示します。 | string | – |
layoutautoは、カードが広いときはコントロールをラベルの横に、狭いときは下に置きます。inlineはスイッチ向けに、常にラベルの横に置きます。stackedはテキストエリア向けに、常に下に置きます。 | "auto" | "inline" | "stacked" | "auto" |
disabled行のフィールドを無効にします。 | boolean | false |
SettingsSelect
すべてのButtonプロップも受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
value選択された値。 | string | – |
onValueChange新しい値とともに呼ばれます。 | (value: string) => void | – |
options選択肢を、順番に。 | { value, label }[] | – |
SettingsChoice
radio groupなので、矢印キーでカード間を移動できます。Base UIのRadioGroupのすべてのプロップも受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
value選択されたオプション。 | string | – |
onValueChange新しいオプションとともに呼ばれます。 | (value: string) => void | – |
options各カードの画像と、その下の名前。 | { value, label, preview }[] | – |
columns1行あたりのカード数。行が狭いと、4は2に減ります。 | 2 | 3 | 4 | 3 |
ratio16:10のプレビュー、または短いものには2:1。 | "card" | "wide" | "card" |
SettingsNumber
formatやsmallStepなど、Base UIのNumberField.Rootのすべてのプロップも受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
value現在の数値。 | number | null | – |
onValueChange数値が変わるたびに呼ばれます。 | (value: number | null) => void | – |
min最小値。−ボタンはそこで無効になります。 | number | – |
max最大値。+ボタンはそこで無効になります。 | number | – |
step1回の押下または矢印キーでどれだけ変化するか。 | number | 1 |
SettingsLink
すべてのanchorプロップも受け付けます。hrefがない場合はbuttonとして描画されます。
| プロパティ | 型 | デフォルト |
|---|---|---|
label行のタイトル。 | ReactNode | – |
descriptionタイトルの下の行。 | ReactNode | – |
externalhrefを新しいタブで開き、シェブロンの代わりに矢印を表示します。 | boolean | false |
| プロパティ | 型 | デフォルト |
|---|---|---|
openオプションを表示します。通常は親のスイッチの値です。 | boolean | – |
| プロパティ | 型 | デフォルト |
|---|---|---|
groups各プレースホルダーグループが持つ行数。 | number[] | [3, 2] |
control各行の右側に表示される形。 | "switch" | "select" | "input" | "switch" |
useSettingsForm
{ values, setValue, errors, dirty, status, save, discard } を返します。
| プロパティ | 型 | デフォルト |
|---|---|---|
values現在保存されている内容。変更があり、編集がない場合、下書きはそれに追従します。 | Values | – |
onSave下書きを保存します。フィールドエラーを表示するには { field: message } を返し、保存バーにメッセージを表示するにはエラーを投げます。 | (values) => void | errors | Promise<void | errors> | – |
validateonSaveの前に実行されます。エラーがあれば保存を中止し、最初の無効なフィールドにフォーカスします。 | (values) => errors | undefined | – |
useSettingsNavigate
シェル内のどこからでもセクションを開く関数を返します。バナーのOpenボタンなどに使えます。サイドバーと同様に、未保存の変更を尊重します。
| プロパティ | 型 | デフォルト |
|---|---|---|
navigateセクションを開きます。未保存の変更がある場合は、保存バーを揺らします。 | (id: string) => void | – |
| キー | アクション |
|---|---|
| Tab | ナビゲーション、セクション、開いている場合は保存バーの順に移動します。 |
| Enter | フォーカスのあるセクションを開きます。 |
| ↑↓ | ステッパーで、数値を1ステップ変更します。Shiftでは10ずつ変化します。 |
| Enter | 検索フィールドで、最初に一致したセクションを開きます。Escapeで検索をクリアします。 |
| ⌘S | 未保存の変更があるときに保存します。WindowsとLinuxではCtrl+Sです。 |
- ナビゲーションはランドマークで、開いているセクションは現在のページとしてマークされます。
- 各セクションは、見出しにちなんだ名前のリージョンです。スマートフォンでは、セクションが開くとフォーカスが見出しに移り、戻ると元の行に戻ります。
- 行はFieldを使うため、ラベル、説明、エラーはコントロールに関連付けられます。
- ブロックされたナビゲーションはpoliteに読み上げられ、保存の失敗はalertとして読み上げられます。
- 保存バーと非表示のパネルはinertであるため、タブ順から外れ、スクリーンリーダーからも隠されます。
- モーション軽減時は、パネルはスライドではなくフェードし、保存バーの揺れはリングに変わります。
使用技術
Settings を構成する無料のHextaUIコンポーネントです。それぞれ単独でインストールできます。
コード
6 個のファイルを components/blocks/settings に追加しました。