1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Select と SearchableSelect の使い分け — 選択肢が 10 件を超えたら検索可能ドロップダウンへ

1
Posted at

この記事は約 4 分で読めます。

筆者プロフィール: ソフトウェアエンジニア。「知った気にならない。いつまでも学び続ける」を信条に、業務と個人開発の両輪で技術を磨いています。AI 駆動開発で複数の個人開発アプリを構築・運用中。
👉 ポートフォリオ: 筆者ホームページ

「プロジェクト選択 (1000 件)」を通常の Select で実装すると地獄。選択肢の件数に応じた UI 選択 で UX が決まります。本記事では、運用中の SaaS 「たすきば Knowledge Relay」 で採用している Select vs SearchableSelect の使い分けルール (KDD §5.8) を整理します。

サービスの機能紹介・画面イメージ・コンセプトは公式プロダクトページをご覧ください。
👉 たすきば Knowledge Relay — 公式プロダクトページ

選択肢の件数別 UI

業務 SaaS の選択肢項目:

選択肢 件数
プロジェクトロール 4 件 (PM / TL / member / viewer)
リスク種別 4 件
担当者 5〜200 件
顧客 10〜500 件
紐付けプロジェクト 10〜1000 件

件数によって、適切な UI が違います


1. 使い分けの基準

基準 Select SearchableSelect
選択肢の件数 〜10 件 10+ 件
件数が固定
件数が動的に増える ×
検索が便利か 不要 必要
キーボード操作 ↑↓ で選択 入力 + ↑↓

「10 件」が暗黙の閾値


2. Select (通常のドロップダウン)

少数の固定選択肢に使う。

<Select value={role} onValueChange={setRole}>
  <SelectTrigger>
    <SelectValue placeholder="ロールを選択" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="PM">PM</SelectItem>
    <SelectItem value="TL">TL</SelectItem>
    <SelectItem value="member">member</SelectItem>
    <SelectItem value="viewer">viewer</SelectItem>
  </SelectContent>
</Select>
特徴 内容
全選択肢表示 一度に見える
スクロール 少しならOK
検索 なし

3. SearchableSelect (検索可能ドロップダウン)

多数の動的な選択肢に使う。

<SearchableSelect
  value={projectId}
  onChange={setProjectId}
  options={projects.map(p => ({ value: p.id, label: p.name }))}
  placeholder="プロジェクトを検索..."
  emptyMessage="該当するプロジェクトがありません"
/>
特徴 内容
入力で絞り込み 候補がフィルタされる
スクロール + 検索 両方で見つけられる
性能 件数増加に強い

4. Base UI Combobox の罠

SearchableSelect を Base UI の Combobox で実装すると、object 形式の items で罠を踏みます。

// ✗ NG: items が object 配列のとき、value 一致でフィルタされない
<Combobox.Items items={[
  { value: 'A', label: 'Alpha' },
  { value: 'B', label: 'Beta' },
]} />

object の場合、filterFunction明示的に value / label をマッチさせる必要 があります。

// ✓ OK: filterFunction を明示
<Combobox.Items
  items={options}
  filterFunction={(item, query) =>
    item.label.toLowerCase().includes(query.toLowerCase())
  }
/>

これをハマって 2 時間溶かしたケースが KDD に記録 されています。


5. value/label が unique でない罠

ユーザ名のように label が重複する可能性がある選択肢:

[山田 太郎 (admin@a.com)]
[山田 太郎 (tanaka@b.com)]

value は user.id で unique なので OK。ただし、label を表示するときに どちらかの情報 (例: email) を併記しないと、ユーザが識別できません。

options={users.map(u => ({
  value: u.id,
  label: `${u.name} (${u.email})`,  // 識別情報を併記
}))}

細かいが、UI 設計で重要なポイント


6. サーバ側でフィルタするパターン

選択肢が 1000 件超 になると、クライアントに全件送るとパフォーマンスが悪い。

<SearchableSelectServerFilter
  fetchOptions={async (query) => {
    const res = await fetch(`/api/projects?q=${encodeURIComponent(query)}&limit=20`);
    return res.json();
  }}
  value={projectId}
  onChange={setProjectId}
/>
仕様 内容
入力ごと API を叩く (debounce 300ms)
返却件数 最大 20 件
性能 件数に関係なく軽量

7. API レスポンスの形式

{
  "options": [
    { "value": "p-001", "label": "ECサイトリニューアル", "subText": "ACME 社 / 進行中" },
    { "value": "p-002", "label": "在庫管理システム", "subText": "XYZ 社 / 完了" }
  ],
  "totalCount": 15,
  "hasMore": false
}
フィールド 用途
subText 追加情報を表示
totalCount 全候補数
hasMore 「他にも候補がある」を UI に表示

8. Label と Input のペア (htmlFor / id)

Select / SearchableSelect には、必ず <Label>htmlFor 付きで関連付けます。

// ✗ NG: htmlFor / id がない
<Label>プロジェクト</Label>
<Select>...</Select>

// ✓ OK
<Label htmlFor="project-select">プロジェクト</Label>
<Select id="project-select">...</Select>
効果 内容
アクセシビリティ スクリーンリーダ対応
クリック範囲拡大 Label クリックで Select にフォーカス
E2E セレクタ ラベル経由のセレクタが使える

KDD §5.10.1.5 に記録: 「Label と Input は htmlFor/id ペア必須」


9. プレースホルダのデザイン

プレースホルダの文言で、ユーザに何をするかを伝えます。

文言 印象
「選択」 何を選ぶか不明
「プロジェクトを選択」 何を選ぶか明示
「プロジェクトを選択 (例: ECサイト)」 例示で具体的

業務 SaaS では、3 番目が最も親切

SearchableSelect の場合は「プロジェクトを検索...」(入力できることが分かる)。


おわりに

UI 選択肢件数 用途
Select 〜10 件 固定選択肢 (ロール / 種別 等)
SearchableSelect 10〜1000 件 動的選択肢 (担当者 / 顧客 等)
SearchableSelectServerFilter 1000+ 件 大量データ (タグ / プロジェクト 等)

件数に応じた UI 選択が、UX を決めます。横展開ルールを文書化することで、新規実装でも統一感を保てます。

本記事の使い分けは、運用中の SaaS 「たすきば Knowledge Relay」 で実装しています。
👉 たすきば Knowledge Relay — 公式プロダクトページ

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?