Senastra — Components
Focus Ring
キーボード操作時のフォーカス可視化。:focus-visible を使い、マウスクリックではリングが表示されず、Tab/キーボード操作時のみ表示されます(WCAG 2.4.7 Focus Visible 準拠)。
Interactive Elements — Tab キーで移動して確認
フォーカスリングトークン
| Token | Value | 用途 |
|---|---|---|
--ring-focus-color | var(--color-border-focus) | リング色(アクセント / テーマ追従) |
--ring-focus-width | 2px | アウトラインの太さ |
--ring-focus-offset | 2px | 要素とリングの隙間 |
使い方
/* 全インタラクティブ要素に自動適用(グローバルルール) */
:focus-visible {
outline: var(--ring-focus-width) solid var(--ring-focus-color);
outline-offset: var(--ring-focus-offset);
}
/* カスタムコンポーネントにも同じトークンで統一 */
.my-widget:focus-visible {
outline: var(--ring-focus-width) solid var(--ring-focus-color);
outline-offset: var(--ring-focus-offset);
}
var(--color-error) に自動切替されます。
Buttons
Primary, Secondary, Ghost, Danger, and Icon-only button variants with sizes and states.
Primary
Standard action button with accent color.
Spec
Secondary
Outlined button with accent border.
Spec
Ghost
Transparent button with subtle hover state.
Spec
Danger
Destructive action button with error color.
Spec
Icon-only
Square icon button in multiple sizes.
Spec
Form States
全入力系コンポーネントで共通する状態表示パターン。順序は ラベル → 入力 → 補助文 → エラー/成功メッセージ に統一(DADS-03)。
全6状態一覧
レイアウト規則 — ラベル→入力→メッセージの順序
<label> に for 属性を必ず付与。
必須項目は <span class="form-label-required">*</span> を末尾に(aria-hidden="true" で読み上げ除外)。
aria-invalid="true"、
メッセージIDを aria-describedby で紐付ける。
.form-help(色: --form-help-color)。
条件付き → .form-message.error または .form-message.success。
エラーメッセージには role="alert" を付けてスクリーンリーダーに即時通知。
フォーム状態トークン
| Token | Value | 用途 |
|---|---|---|
--form-gap | var(--space-4) = 16px | フォームグループ間の余白 |
--form-label-gap | var(--space-1-5) = 6px | ラベル↔入力の隙間 |
--form-message-gap | var(--space-1) = 4px | 入力↔補助文の隙間 |
--form-label-color | var(--color-text-primary) | ラベルテキスト色 |
--form-help-color | var(--color-text-tertiary) | 補助文テキスト色 |
--form-error-color | var(--color-error) | エラーメッセージ色 |
--form-success-color | var(--color-success) | 成功メッセージ色 |
ARIA パターン(コピー用)
<!-- エラー状態 -->
<div class="form-group">
<label class="form-label" for="email">
メールアドレス
<span class="form-label-required" aria-hidden="true">*</span>
</label>
<input id="email" type="email" class="form-input error"
aria-invalid="true" aria-describedby="email-error">
<span id="email-error" class="form-message error" role="alert">
<span class="form-message-icon" aria-hidden="true">⚠</span>
有効なメールアドレスを入力してください
</span>
</div>
<!-- 成功状態 -->
<div class="form-group">
<label class="form-label" for="email">メールアドレス</label>
<input id="email" type="email" class="form-input success"
value="you@example.com" aria-describedby="email-ok">
<span id="email-ok" class="form-message success">
<span class="form-message-icon" aria-hidden="true">✓</span>
確認済みのアドレスです
</span>
</div>
Form Layout
フォームレイアウトの余白・並び規格(DADS-10)。 フィールド間・行間・セクション間の間隔をトークンで統一し、 単カラム / 横並び / インラインラベルの3パターンを定義する。
単カラム(推奨: max-width 480px)
横並び行(form-row)+ セクション分割
インラインラベル(左ラベル配置)
スペーシングトークン(--form-layout-* / --form-*)
| 用途 | トークン | 値 | 適用箇所 |
|---|---|---|---|
| フィールド間(縦) | --form-field-gap | --space-5 (20px) | .form-layout の gap |
| フィールド間(横並び) | --form-row-gap | --space-4 (16px) | .form-row の gap |
| セクション間 | --form-section-gap | --space-8 (32px) | セクション見出しの前マージン |
| ラベル↔入力 | --form-label-gap | --space-1-5 (6px) | .form-group の gap |
| 入力↔補助文 | --form-message-gap | --space-1 (4px) | 補助文・エラーメッセージの上マージン |
| インラインラベル幅 | --form-inline-label-width | 140px | 左ラベル配置時の固定幅 |
| フォーム最大幅 | --form-max-width | 480px | 単カラムフォームの推奨幅上限 |
実装パターン
<!-- 単カラム --> <form class="form-layout"> <!-- gap: --form-field-gap; max-width: --form-max-width --> <div class="form-group">...</div> <div class="form-group">...</div> </form> <!-- 横並び行 --> <div class="form-row"> <!-- grid 2-col, gap: --form-row-gap --> <div class="form-group">...</div> <div class="form-group">...</div> </div> <!-- インラインラベル --> <div class="form-group form-group-inline"> <label class="form-label">...</label> <!-- width: --form-inline-label-width --> <input class="form-input"> </div>
Disabled / Readonly
disabled と readonly の規約分離(DADS-11)。
2つは見た目が似ているが、意味・送信挙動・アクセシビリティが異なる。用途に応じて正しく使い分ける。
disabled 属性のみ(aria-disabled="true" は interactive 要素に)readonly 属性 または aria-readonly="true"使い分けガイド
| 状況 | 使うべき状態 | 理由 |
|---|---|---|
| 権限がないため変更できない | disabled | 送信しても無意味・操作自体禁止を明示 |
| 確認画面の入力値を表示 | readonly | 送信時に値を含めたい・フォーカスで内容確認できる |
| 自動計算された結果フィールド | readonly | 手動変更不可だが値はサーバーに送りたい |
| プランの上限により機能無効化 | disabled | ユーザーが変更できない状態を明確に示す |
| ログイン中ユーザーのメールアドレス | readonly | 表示・コピーは可能だが変更は不可 |
コンポーネントトークン(--form-disabled-* / --form-readonly-*)
| トークン | 値 | 用途 |
|---|---|---|
--form-disabled-bg | --color-bg-inset | disabled 背景色 |
--form-disabled-color | --color-text-tertiary | disabled 文字色 |
--form-disabled-opacity | --opacity-50 (0.5) | disabled 不透明度 |
--form-disabled-cursor | not-allowed | disabled カーソル |
--form-readonly-bg | --color-bg-subtle | readonly 背景色 |
--form-readonly-color | --color-text-secondary | readonly 文字色 |
--form-readonly-border-style | dashed | readonly ボーダースタイル(破線で区別) |
--form-readonly-cursor | default | readonly カーソル(通常矢印) |
Message Style
補助文・エラーメッセージ・成功メッセージの文体ガイド(DADS-12)。
詳細は docs/07-message-style.md を参照。
補助文(Help Text)
エラーメッセージ(Error Message)
文体ルール — 良い例 / 悪い例
| 種別 | ✅ 良い例 | ❌ 悪い例 | 理由 |
|---|---|---|---|
| エラー | メールアドレスを正しく入力してください | 無効な入力です | 何が問題か・どう直すかが不明 |
| エラー | パスワードは 8 文字以上で入力してください | パスワードエラー | 体言止め・解決策なし |
| エラー | 使用できない文字が含まれています(半角英数字のみ) | 不正な文字が含まれています | 「不正」はユーザーを責める表現 |
| 補助文 | 例: 03-1234-5678 | ここに電話番号を入力してください | 冗長・ラベルと重複 |
| 成功 | 保存しました | 操作が完了しました | 具体的に何が起きたか不明 |
ARIA 実装(エラー時)
<div class="form-group">
<label class="form-label" for="email">メールアドレス</label>
<input class="form-input error"
id="email" type="email"
aria-invalid="true"
aria-describedby="email-error">
<span class="form-message error" id="email-error" role="alert">
メールアドレスを正しく入力してください(例: taro@example.com)
</span>
</div>
<!-- role="alert" → 動的挿入時にスクリーンリーダーが即座に読み上げる -->
<!-- aria-invalid="true" → 入力欄本体に設定(メッセージ要素ではない) -->
Textarea Counter
上限付きテキストエリアの文字数カウンター。通常 / 警告(80%+)/ 超過(100%+) の3状態で色・ボーダー・バーが連動して変化する(DADS-04)。
状態一覧(上限 200文字)
文字数カウンタートークン
| Token | Value | 用途 |
|---|---|---|
--form-counter-color | var(--color-text-tertiary) | 通常状態の文字色 |
--form-counter-warn-color | var(--color-warning) | 警告状態(≥80%)の文字色 |
--form-counter-over-color | var(--color-error) | 超過状態(≥100%)の文字色 |
--form-counter-warn-threshold | 0.8 | 警告開始しきい値(JS で参照可) |
実装パターン(HTML + JS)
<!-- HTML -->
<div class="form-group">
<label class="form-label" for="body">本文</label>
<div class="textarea-wrapper">
<textarea id="body" class="form-textarea"
data-maxlength="200" rows="4"></textarea>
<div class="char-counter" id="body-counter">
<span class="char-counter-bar">
<span class="char-counter-bar-fill" style="width:0%"></span>
</span>
<span class="char-counter-text">0 / 200</span>
</div>
</div>
</div>
<script>
function initCharCounter(textarea) {
const max = parseInt(textarea.dataset.maxlength, 10);
const root = getComputedStyle(document.documentElement);
const warnAt = parseFloat(
root.getPropertyValue('--form-counter-warn-threshold').trim()
) || 0.8;
const counter = document.getElementById(textarea.id + '-counter');
const fill = counter?.querySelector('.char-counter-bar-fill');
const label = counter?.querySelector('.char-counter-text');
function update() {
const len = textarea.value.length;
const pct = len / max;
const over = len > max;
const warn = !over && pct >= warnAt;
counter.className = 'char-counter' + (over ? ' over' : warn ? ' warn' : '');
textarea.classList.toggle('error', over);
textarea.classList.toggle('warn', warn);
if (fill) fill.style.width = Math.min(pct * 100, 100) + '%';
if (label) label.textContent =
(over ? '⚠ ' : '') + len + ' / ' + max;
textarea.setAttribute('aria-invalid', String(over));
}
textarea.addEventListener('input', update);
update();
}
document.querySelectorAll('textarea[data-maxlength]')
.forEach(initCharCounter);
</script>
Search Box
3サイズ規格(sm / md / lg)を持つ検索ボックス。サイズモディファイアを切り替えるだけで高さ・余白・フォント・アイコンが連動して変わる(DADS-05)。
サイズ規格 — sm / md / lg
ライブデモ — 入力でクリアボタン・フォーカスリングを確認
検索ボックストークン
| Token | sm | md | lg |
|---|---|---|---|
--search-*-height | 32px | 40px | 52px |
--search-*-padding-x | 8px | 12px | 16px |
--search-*-font | 12px | 13px | 15px |
--search-*-icon | 14px | 16px | 20px |
--search-*-radius | 8px | 8px | 16px |
実装パターン
<!-- sm: ツールバー・サイドバー内 -->
<div class="search-box search-sm"> ... </div>
<!-- md: 標準ページ検索 -->
<div class="search-box search-md"> ... </div>
<!-- lg pill elevated: ヒーロー / スポットライト -->
<div class="search-box search-lg search-pill search-elevated"> ... </div>
<!-- クリアボタン有効化 (JS) -->
input.addEventListener('input', () => {
box.classList.toggle('has-value', input.value.length > 0);
});
clear.addEventListener('click', () => {
input.value = '';
box.classList.remove('has-value');
input.focus();
});
Combobox
WAI-ARIA Combobox Pattern 1.2 準拠。キーボード操作・フィルタリング・選択状態を含む。 ↓↑でナビゲーション、Enterで選択、Escで閉じる。
閉じた状態
開いた状態(選択なし)
- React
- Vue
- Svelte
- Angular
- Solid
選択済み状態
- React
- Vue
- Svelte
- Angular
- Solid
ライブデモ — フィルタリング付きオートコンプリート
Select-only(フィルターなし)
- JavaScript
- TypeScript
- Python
- Rust
- Go
- Swift
- Kotlin
Autocomplete(入力でフィルタリング)
ARIA パターン(WAI-ARIA 1.2 Combobox)
| 属性 | 要素 | 説明 |
|---|---|---|
role="combobox" | input の親コンテナ | コンボボックスウィジェット全体 |
aria-haspopup="listbox" | combobox | リストボックスポップアップを持つ |
aria-expanded | combobox | リストボックスの開閉状態(true/false) |
aria-controls | combobox | 関連するリストボックスの ID |
aria-activedescendant | combobox | 現在フォーカスのあるオプションの ID |
aria-autocomplete="list" | input | フィルタリングあり(なしの場合は "none") |
role="listbox" | ul | オプションリスト |
role="option" | li | 各選択肢 |
aria-selected | option | 選択状態(true/false) |
コンポーネントトークン(--combobox-*)
| トークン | 参照先 | 用途 |
|---|---|---|
--combobox-height | --density-row-height | 入力行の高さ(密度対応) |
--combobox-padding-x | --space-3 | 水平パディング |
--combobox-bg | --color-surface | 入力エリア背景 |
--combobox-border | --color-border | 通常時ボーダー |
--combobox-border-focus | --color-border-focus | フォーカス時ボーダー |
--combobox-radius | --radius-md | 角丸 |
--combobox-listbox-shadow | --shadow-md | リストボックス影 |
--combobox-option-height | --density-row-height | オプション行高(密度対応) |
--combobox-option-hover-bg | --color-bg-subtle | ホバー時背景 |
--combobox-option-active-bg | --color-selected | キーボードフォーカス背景 |
--combobox-option-selected-bg | --color-selected-strong | 選択済み背景 |
--combobox-option-check-color | --color-accent | 選択チェックマーク色 |
実装パターン(WAI-ARIA 1.2)
<!-- Select-only combobox -->
<div class="combobox-wrapper"
role="combobox"
aria-haspopup="listbox"
aria-expanded="false"
aria-controls="my-listbox">
<div class="combobox-input-row">
<input class="combobox-input" type="text"
placeholder="選択…" readonly
aria-autocomplete="none">
<svg class="combobox-chevron" ...>...</svg>
</div>
<ul class="combobox-listbox" id="my-listbox" role="listbox">
<li class="combobox-option" role="option"
aria-selected="false" data-value="option-1">
<svg class="combobox-option-check">...</svg>
選択肢 1
</li>
</ul>
</div>
<!-- キーボード操作 -->
<!-- ↓↑: オプション間ナビゲーション(aria-activedescendant 更新) -->
<!-- Enter / Space: 選択確定・リスト閉じる -->
<!-- Escape: リスト閉じる・入力値リセット -->
<!-- Tab: リスト閉じる(フォーカス移動) -->
<!-- Alt + ↓: リスト開く(select-only モード) -->
Heading
h1〜h4 の見出し階層とセクションラベル(eyebrow)の規約(DADS-08)。 サイズ・ウェイト・行間・余白をトークンで統一し、見出し構造がドキュメントアウトラインを正しく形成することを保証する。
見出しスケール
セクションラベル + 見出し + リード文
デザインシステムで
一貫性を実現する
トークンベースの設計により、すべてのプロダクトで統一されたUIを維持します。
トークン設計の原則
Primitive → Semantic → Component の3層構造でトークンを管理します。
コンポーネントトークン
使用例: --form-label-gap
フォームラベルと入力欄の間隔を統一するトークンです。
余白規則
| ルール | トークン | 値 | 説明 |
|---|---|---|---|
| 見出し↔直後コンテンツ | --heading-gap-below | --space-4 (16px) | 見出しの下マージン |
| セクション間マージン | --heading-gap-above | --space-8 (32px) | 前コンテンツ↔次見出し |
| ラベル↔見出し | --heading-label-gap | --space-2 (8px) | eyebrow ↔ 見出し間 |
コンポーネントトークン(--heading-*)
| トークン | 参照先 | 用途 |
|---|---|---|
--heading-1-size | --text-4xl (32px) | h1 フォントサイズ |
--heading-2-size | --text-3xl (24px) | h2 フォントサイズ |
--heading-3-size | --text-xl (20px) | h3 フォントサイズ |
--heading-4-size | --text-lg (18px) | h4 フォントサイズ |
--heading-weight-display | 700 | h1 フォントウェイト |
--heading-weight | 600 | h2–h4 フォントウェイト |
--heading-line-height | --leading-tight (1.25) | すべての見出し行間 |
--heading-color | --color-text-primary | 見出し文字色 |
--heading-label-size | --text-xs (12px) | セクションラベルサイズ |
--heading-label-weight | 600 | セクションラベルウェイト |
--heading-label-color | --color-text-secondary | セクションラベル文字色 |
--heading-label-tracking | --tracking-widest (0.1em) | ラベル文字間隔 |
--heading-label-transform | uppercase | ラベル大文字変換 |
見出し構造ルール(WCAG 1.3.1 — レベルA)
<!-- ✅ 正しい例: 見出しレベルをスキップしない -->
<h1 class="heading-1">ページタイトル</h1>
<h2 class="heading-2">セクション</h2>
<h3 class="heading-3">サブセクション</h3>
<!-- ❌ NG: 見た目でh4を選ぶ(h2の直下にh4を置く) -->
<!-- h2 → h4 はドキュメントアウトラインを壊す -->
<!-- セクションラベル(eyebrow)パターン -->
<span class="heading-label" aria-hidden="true">機能紹介</span>
<h2 class="heading-2">デザインシステムで一貫性を実現する</h2>
<!-- aria-hidden="true" でスクリーンリーダーはラベルを重複読み上げしない -->
Status
ステータス表示の非色依存化ルール(DADS-09)。WCAG 1.4.1「色の使用」により、 情報は色だけで伝えてはいけない。アイコン + ラベル + 色の 3点セットが必須。
Status Badge(インライン表示)
コンポーネントトークン(--status-*)
| トークン | 参照先 | 用途 |
|---|---|---|
--status-icon-size | 16px | アイコン基本サイズ |
--status-gap | --space-1-5 | アイコン↔テキスト間隔 |
--status-success-color | --color-success | 成功 テキスト・アイコン色 |
--status-success-bg | --color-success-subtle | 成功 バッジ背景 |
--status-warning-color | --color-warning | 警告 テキスト・アイコン色 |
--status-warning-bg | --color-warning-subtle | 警告 バッジ背景 |
--status-error-color | --color-error | エラー テキスト・アイコン色 |
--status-error-bg | --color-error-subtle | エラー バッジ背景 |
--status-info-color | --color-info | 情報 テキスト・アイコン色 |
--status-info-bg | --color-info-subtle | 情報 バッジ背景 |
--status-neutral-color | --color-text-secondary | 中立 テキスト・アイコン色 |
--status-neutral-bg | --color-bg-subtle | 中立 バッジ背景 |
DADS-09 準拠チェックリスト(WCAG 1.4.1)
<!-- ✅ 準拠: アイコン + ラベル + 色の3点セット --> <span class="status-indicator status-success"> <svg class="status-icon" aria-hidden="true">...チェックアイコン...</svg> 完了 </span> <!-- ✅ バッジ形式 --> <span class="status-badge status-warning"> <svg class="status-icon" aria-hidden="true">...警告アイコン...</svg> 警告 </span> <!-- アイコンは aria-hidden="true" にしてテキストラベルで意味を伝える --> <!-- スクリーンリーダー専用テキストが必要なら .sr-only クラスを使う --> <!-- ❌ 非準拠: 色のみ(テキスト・アイコンなし) --> <span class="status-dot dot-success"></span>
Inputs
Text, Password, Textarea, and Select inputs with various states.
Text Input
Standard text input field.
Spec
Password Input
Password field with show/hide toggle.
Spec
Textarea
Multi-line text input.
Spec
Select / Dropdown
Native select element.
Spec
Form Group
Input with label and helper text.
Spec
Checkboxes & Radio
Selection controls with labels and states.
Checkbox
Multi-select checkbox control.
Spec
Radio
Single-select radio control.
Spec
Toggle Switch
On/Off toggle control.
Toggle Switch
Binary toggle control with on/off states.
Spec
Badges & Tags
Status badges and closable tags.
Badges
Compact status and category badges.
Spec
Closable Tags
Tags with remove button.
Spec
Alerts / Banners
Status alerts with icons and dismiss buttons.
Alert - Success
Positive confirmation message.
Spec
Alert - Warning
Cautionary message.
Spec
Alert - Error
Error or failure message.
Spec
Alert - Info
Informational message.
Spec
Toast / Notification
Floating notifications with auto-dismiss timer.
Toast Notification
Small notification displayed in corner with dismiss and auto-close.
Spec
Modal / Dialog
Confirmation dialog with overlay.
Modal Dialog
Standard confirmation dialog overlay.
Confirm Action
Spec
Dropdown Menu
Menu with items, dividers, icons, and keyboard shortcuts.
Dropdown Menu
Contextual menu with various item types.
Spec
Tooltip
Directional tooltips (top, bottom, left, right).
Tooltip Positions
Tooltips in all directions.
Spec
Progress
Determinate / Indeterminate プログレスバーと Circular Spinner の標準化(DADS-07)。
サイズ 3 段階・セマンティックカラー 4 種・正しい role="progressbar" ARIA 付き。
Linear — Determinate
値バリエーション(sm / md / lg)
セマンティックカラー
Indeterminate & Spinner
不定形プログレスバー
Circular Spinner(sm / md / lg)
コンポーネントトークン(--progress-*)
| トークン | 参照先 | 用途 |
|---|---|---|
--progress-height | --space-2 (8px) | 標準トラック高 |
--progress-height-sm | --space-1-5 (6px) | 細めトラック |
--progress-height-lg | --space-3 (12px) | 太めトラック |
--progress-track-bg | --color-bg-inset | トラック背景色 |
--progress-fill-color | --color-accent | 塗り色(デフォルト) |
--progress-fill-success/warning/danger | 各セマンティック色 | 状態別塗り色 |
--progress-radius | --radius-full | Pill 型角丸 |
--progress-duration | 300ms | fill 変化トランジション |
--progress-spinner-size | 40px | スピナー直径(md) |
--progress-spinner-width | --stroke-medium (2px) | スピナー線幅 |
--progress-spinner-color | --color-accent | スピナーアクティブ弧色 |
--progress-spinner-track | --color-bg-inset | スピナートラック色 |
--progress-spinner-duration | 700ms | 1回転の時間 |
ARIA パターン
<!-- Determinate -->
<div class="progress-track"
role="progressbar"
aria-valuenow="60"
aria-valuemin="0"
aria-valuemax="100"
aria-label="インストール進捗">
<div class="progress-fill" style="width: 60%"></div>
</div>
<!-- Indeterminate: aria-valuenow を省略 -->
<div class="progress-track"
role="progressbar"
aria-valuemin="0"
aria-valuemax="100"
aria-label="読み込み中">
<div class="progress-fill progress-indeterminate"></div>
</div>
<!-- Circular spinner -->
<div class="progress-spinner"
role="status"
aria-label="読み込み中"></div>
Tabs
Horizontal tab bar with active/inactive/disabled states.
Tab Navigation
Horizontal tab navigation.
Spec
Breadcrumb
Navigation breadcrumb trail.
Breadcrumb Navigation
Hierarchical navigation path.
Spec
Avatar
User avatars with sizes, initials fallback, and status indicators.
Avatar Sizes
Avatar in small, medium, and large sizes.
Spec
Avatar with Status
Avatar with online/offline status indicator.
Spec
Table
Data table with header, rows, hover, selected, and striped variants.
Table Rows
Standard data table with various row states.
| Name | Role | Status | |
|---|---|---|---|
| Alice Johnson | Designer | Active | alice@example.com |
| Bob Smith | Developer | Active | bob@example.com |
| Carol White | Manager | Pending | carol@example.com |
| David Brown | Engineer | Inactive | david@example.com |