コンテンツを特定の基準(日付・価格・名前・評価など)で並べ替えるUIコンポーネント。ドロップダウン・タブ・ボタングループなど複数の形式があり、「現在どのキーで・どの方向(昇順/降順)に並んでいるか」をユーザーに常に伝えることが設計の核。
この記事を読むと、ソートUIの形式選択(ドロップダウン vs チップ vs テーブルヘッダー)・昇順/降順のアイコン表現・現在のソート状態の可視化・URLへの状態永続化が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
コンテンツを特定のキー(日付・価格・名前・評価など)と方向(昇順・降順)で並べ替えるUIコンポーネント。データの量・ソートキーの数・UIの文脈(リスト・テーブル・グリッド)によって最適な形式が変わる。
FilterとSortの違い:Filterは「表示するコンテンツを絞る(件数が変わる)」。Sortは「全コンテンツを別の順番で並べ替える(件数は変わらない)」。両方が必要な場合は同じUIエリアに並べて配置する。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- コンテンツを複数の基準で並べ替えたい場合(最新順・人気順・価格順など)
- ユーザーが自分の優先順位でリストを整理したい記事一覧・商品一覧・管理画面
- テーブルの各カラムで並べ替えが必要なデータテーブル
3.2 When NOT to use
- コンテンツが少量(10件以下)で全件見渡せる → 固定順で表示して十分
- ソート基準が1つしかない → 常に同じ順で表示する
- コンテンツが時系列のみ(ブログ記事) → 「新しい順」をデフォルトにして選択肢を省く
3.3 代替UI(Alternatives)
- 条件で絞り込む →
Filter - カテゴリ切り替え →
Tabs・セグメントコントロール - テーブルの全カラムでソート → テーブルヘッダー型(
aria-sort必須)
4. 設計判断の核(Decision Principles)
Sortの核は「現在何のキーで・どの方向に並んでいるか」を常にユーザーに見せること——ソート状態が分からないと、なぜこの順番で並んでいるのかユーザーが理解できない。
判断の優先順位:① 形式選択 → ② 現在状態の可視化 → ③ 昇順/降順トグル → ④ URL永続化
- 形式の選択基準:ソートキーが2〜3個なら常時表示のチップ型。4個以上ならドロップダウン型。テーブルなら各カラムヘッダーにソートボタンを内蔵する
- 現在のソートキーを必ずハイライト:どのキーがアクティブかを色・太字・アイコンで明示する。ユーザーが「今何順に並んでいるか」を一目で把握できる必要がある
- 昇順/降順は同じボタンを再クリックでトグル:同じキーを再クリックすると昇順↔降順が切り替わるパターンが最も直感的。テーブルヘッダー型ではこの挙動が標準
- デフォルトのソートキーを明示する:「新しい順」「人気順」など、ページを開いた時点のソート基準をデフォルト選択として示す。ユーザーは「なぜこの順番?」と思わなくなる
5. 状態設計(States)
5.1 必須状態(Required)
- Default(デフォルトキー選択中):初期表示のソート状態。どのキーがデフォルトかを明示
- Active(ソート適用中):選択中のキーをハイライト、矢印アイコンで方向を示す
5.2 条件付き状態(Conditional)
- Loading:サーバーサイドソートで結果待ち中のスケルトン
- 昇順:矢印が上向き(↑)
- 降順:矢印が下向き(↓)
5.3 State Gallery
| 状態 | 必須 | 何を伝えるか |
|---|---|---|
| Default | ✅ | デフォルトのソート基準 |
| Active(昇順) | ✅ | このキーで昇順に並んでいる |
| Active(降順) | ✅ | このキーで降順に並んでいる |
| Loading | — | ソート処理中 |
6. バリエーション設計(Variants)
ソートキーの数とUIの文脈で形式を選ぶ。
| バリアント | キー数 | 配置 | 適したUI |
|---|---|---|---|
| チップ型(Toggle Group) | 2〜3個 | コンテンツ上部 | リスト・カードグリッド |
| ドロップダウン型 | 4個以上 | ツールバー | 記事一覧・商品一覧 |
| テーブルヘッダー型 | — | テーブルのth要素 | データテーブル |
禁止パターン:ソートを適用してもどのキーがアクティブか視覚的に分からない → 色・太字・アイコンのいずれかで必ずアクティブ状態を示す。
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
- ソート状態の不可視化:どのキーでソートされているか分からず、ユーザーが順番の意味を理解できない
- 昇順/降順の表示なし:「更新日順」で並んでいることは分かるが、新しい順か古い順かが分からない
- テーブルヘッダーに
aria-sortがない:スクリーンリーダーがソート状態を伝えられない
7.1 Bad(典型3つ)
- ドロップダウンで「更新日」を選んだが、どの選択肢がアクティブかドロップダウン外からは分からない
- 昇順・降順の切り替えが別々のボタンで実装されており、2つのボタンが常に表示されてUIが複雑になっている
- テーブルの列ヘッダーをクリックするとソートされるが、どの列でソートされているか・昇順か降順かが何も示されない
7.2 Good(対になる3つ)
- ドロップダウンのトリガーボタンに現在のソートキーを表示する(「並び順:更新日 ↓」)
- 同じキーを再クリックすると昇順↔降順がトグルし、現在の方向を矢印アイコン(↑/↓)で示す
- テーブルヘッダーボタンに
aria-sort="ascending"またはaria-sort="descending"を付与し、アクティブ列をハイライトする
7.3 How to fix(手順)
- ドロップダウンのトリガーボタンテキストを「並び順」から「並び順:[現在のキー] [↑/↓]」に変更する
- チップ型・ドロップダウン型に昇順/降順トグルボタンを追加する(または同じキーの再クリックでトグル)
- テーブルヘッダーの
<th>内の<button>にaria-sort属性を動的に付与する - ソート状態をURLの
?sort=date&dir=desc形式で永続化する
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
TabでソートコントロールにフォーカスEnter/Spaceでソートキーを選択・昇順/降順をトグル- ドロップダウン型:
Enterで開く、↑・↓で選択肢移動、Escapeで閉じる
Focus
- フォーカスリングをソートボタン・ドロップダウントリガーに表示する
Screen Reader
- テーブルヘッダー型は
aria-sortで並び順を伝える:<th> <button aria-sort="descending">更新日 ↓</button> </th> - チップ型・ドロップダウン型は
aria-labelで状態を説明する:<button aria-pressed="true" aria-label="更新日順(降順)でソート中">更新日</button> - ソート変更後に
aria-live="polite"で「更新日の新しい順に並べ替えました」と通知する
Touch / Pointer
- ソートボタン・ドロップダウントリガーのタップ領域は最低44×44px
- テーブルヘッダーのソートボタンは十分な高さを確保する
10. 実装メモ(Implementation Notes)
- ソート状態は
useSearchParamsでURLに永続化するのが最善。?sort=date&dir=descの形式でページリロード・共有URLでも状態が復元される - テーブルヘッダー型のソートは shadcn/ui の
DataTable(TanStack Table ベース)がcolumn.getIsSorted()を使ってaria-sortを自動管理する - 昇順/降順のアイコンは Lucide の
ArrowUp/ArrowDown/ArrowUpDown(未ソート)を使うと統一感が出る - クライアントサイドソートは
Array.sort()+useMemoで実装し、依存配列にsortKeyとsortDirを含める
11. 関連リンク
- 関連するUIデザイン原則: 視覚的階層 (Visual Hierarchy), スキャンしやすさ (Scannability), フィードバック (Feedback)
- 用語集(定義): 視覚的階層 (Visual Hierarchy)
- 関連するUIコンポーネント(横): Filter(フィルター), Search(検索), Table(テーブル), List(リスト)
12. まとめ
Sortの設計は「現在何のキーで・どの方向に並んでいるか」を常に見せることが最重要です。迷ったら 4. 設計判断の核 に戻り、ソートキーのハイライト・昇順/降順アイコン・aria-sort の3点を確認してください。Filterと組み合わせて使う場合は同じツールバーに並べ、ソート状態をURLに永続化することでブラウザバックへの対応も同時に解決します。