ユーザーのアバターやリンクにホバーした時に、ユーザープロフィール・記事プレビュー・リポジトリ情報などをリッチなカード形式で表示するUIコンポーネント。Twitterのユーザー名ホバー・GitHubのリポジトリリンクホバーが典型例。Tooltipより情報量が多く、Popoverよりも受動的(クリック不要で表示)なのが特徴。
この記事を読むと、Tooltip・Popoverとの明確な使い分け・ホバー遅延(300〜500ms)の設計・キーボードユーザーへのフォールバック設計・フォーカス時にも表示する実装が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
ユーザーのアバター・ハンドルネーム・記事リンクなどにホバーした時に、その対象に関連するリッチなプレビュー情報をカード形式で表示するUIコンポーネント。Tooltipより情報量が多く(アバター・フォロワー数・プロフィール文など)、Popoverよりも受動的(クリック不要で表示)。
Tooltip / Popover / Hover Cardの関係:
| 表示トリガー | コンテンツ | インタラクション | |
|---|---|---|---|
| Tooltip | ホバー/フォーカス | 短いテキスト(1〜2行) | 不可 |
| Hover Card | ホバー/フォーカス | リッチなカード(画像・複数行) | 可(ボタン・リンク含む) |
| Popover | クリック | 設定・フォーム | 可(フォームも含む) |
Hover CardはTooltipとPopoverの中間——ホバーで表示されるが、Tooltipより情報量が多くインタラクティブな要素(フォローボタンなど)を含める。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- ユーザーのアバター/ハンドル名にホバーした時のプロフィールプレビュー(SNS・チームツール)
- 記事・コンテンツのリンクにホバーした時のプレビュー(タイトル・サムネイル・要約)
- GitHubリポジトリリンクにホバーした時のスター数・説明のプレビュー
- ページ遷移前にコンテンツの概要を先に見せたい場面
3.2 When NOT to use
- 必須の情報を表示する → モバイルでホバーできず情報にアクセスできない
- 短いテキスト(1〜2行)のみ → Tooltipで十分
- フォーム・複雑な設定 → Popoverを使う
- 主要なコンテンツとして機能させる → 独立したページ・Cardコンポーネントを使う
3.3 代替UI(Alternatives)
- 短いテキストの補足 →
Tooltip - クリックで開くインタラクティブパネル →
Popover - コンテンツを常時表示 →
Card - ページ全体のコンテンツ → リンク先ページ
4. 設計判断の核(Decision Principles)
Hover Cardの核は「ホバー遅延」と「カード上でのホバー維持」——遅延なしで即時表示するとUIが騒がしくなり、カード上にカーソルを移動すると閉じる実装ではカード内のボタンを押せない。
判断の優先順位:① ホバー遅延(300〜500ms)→ ② カード上でのホバー維持 → ③ フォーカス時の表示(キーボード対応)→ ④ 閉じる遅延(200〜300ms)
- 表示遅延(300〜500ms)を必ず設ける:カーソルがUI上を通過するたびにHover Cardが表示されると画面が騒がしくなる。
setTimeoutで意図的なホバーとカーソル通過を区別する - カード上にカーソルを移動しても閉じない:ユーザーがカード内のボタン(フォローボタンなど)をクリックしようとカーソルを移動すると、カードが閉じてしまう設計は典型的な失敗。
onMouseEnterカードでタイマーをクリアする - 閉じる遅延(200〜300ms)を設ける:トリガーからカーソルが外れた瞬間に即座に閉じると、カード上にカーソルを移動する前に閉じてしまう。閉じる遅延でカードへの移動を可能にする
- フォーカス時にも表示する:ホバーのみで表示するとキーボードユーザーがHover Cardの情報にアクセスできない。
onFocusでも表示して、onBlurで非表示にする
5. 状態設計(States)
5.1 必須状態(Required)
- Hidden(非表示):デフォルト状態
- Visible(表示中):ホバー/フォーカス後の表示遅延が経過した後
5.2 条件付き状態(Conditional)
- Loading:カードのコンテンツをサーバーから取得中(スケルトン表示)
- Error:コンテンツ取得失敗
5.3 State Gallery
| 状態 | 必須 | 何を伝えるか |
|---|---|---|
| Hidden | ✅ | 通常状態(Hover Cardは非表示) |
| Visible | ✅ | リッチなプレビュー情報 |
| Loading | — | コンテンツ取得中 |
6. バリエーション設計(Variants)
コンテンツの種類によって使い分ける。
| バリアント | コンテンツ | 使用例 |
|---|---|---|
| ユーザープロフィール | アバター・名前・bio・フォロワー数 | SNS・チームツール |
| 記事プレビュー | タイトル・サムネイル・要約・読了時間 | ブログ・ドキュメント |
| リポジトリ情報 | スター数・説明・言語・最終更新 | GitHub風ツール |
| 商品プレビュー | 画像・価格・評価 | ECサイト |
禁止パターン:Hover Cardにスクロールが必要なほど大量のコンテンツを詰め込む → 読み切れないうちにカーソルが外れてカードが閉じる。Hover Cardは「概要を一瞬で把握する」ためのもので、詳細はリンク先ページで見せる。
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
- 即時表示(遅延なし):
onMouseEnterで即座にカードを表示し、リスト上をスクロールするたびに次々とHover Cardが表示されてUIが煩雑になる - カード上に移動すると閉じる:トリガーの
onMouseLeaveで即座に閉じる実装になっており、ユーザーがカード内の「フォロー」ボタンをクリックしようとするとカードが閉じてしまう - フォーカス対応なし:ホバーのみで表示し、キーボードユーザーがTabキーでリンクにフォーカスしてもHover Cardが表示されず、プレビュー情報にアクセスできない
7.1 Bad(典型3つ)
onMouseEnter={() => setVisible(true)}で遅延なし即時表示。長いリストをスクロールするたびにHover Cardが乱立する- トリガーの
onMouseLeaveでsetVisible(false)が即時実行され、カード上にカーソルを移動する前に閉じてしまう onFocusの実装がなく、キーボードでリンクにフォーカスしてもHover Cardが表示されない
7.2 Good(対になる3つ)
onMouseEnterでsetTimeout(400ms)の表示タイマーを設定し、onMouseLeaveでタイマーをクリアする。意図的なホバーのみカードを表示するonMouseLeaveでsetTimeout(300ms)の閉じるタイマーを設定し、カード自体のonMouseEnterでそのタイマーをクリアする。カード上にカーソルを移動してもカードが閉じないonFocus={() => setVisible(true)}とonBlur={() => setVisible(false)}を追加してキーボードフォーカス時にも表示する
7.3 How to fix(手順)
showTimer/hideTimerの2つのuseRefを用意し、表示・非表示を独立したタイマーで管理する- トリガーの
onMouseEnterで表示タイマー(400ms)を設定し、onMouseLeaveで非表示タイマー(300ms)を設定する - カード自体の
onMouseEnterで非表示タイマーをクリアし、onMouseLeaveで再度非表示タイマーを設定する - トリガーに
onFocus/onBlurを追加してキーボード対応を実装する
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
Tabでトリガー要素にフォーカスした時にHover Cardを表示するTabでカード内のインタラクティブ要素(ボタン・リンク)にフォーカスを移すEscapeでHover Cardを閉じる- フォーカスがトリガー要素から外れたらHover Cardを閉じる
Focus
- キーボードフォーカス時(
onFocus)にHover Cardを表示する - カード内にフォーカス可能な要素がある場合、Tabキーでフォーカスを移せる
Screen Reader
<!-- トリガー -->
<a
href="/users/hikaru"
aria-describedby="hovercard-hikaru"
>
@hikaru
</a>
<!-- Hover Card -->
<div
id="hovercard-hikaru"
role="tooltip"
>
Hikaru Tanaka・プロダクトデザイナー・891フォロワー
</div>
Hover Cardがインタラクティブな要素(ボタン・リンク)を含む場合は role="tooltip" でなく role="dialog" を検討する。ただしダイアログにするとフォーカス管理が複雑になるため、Popoverへの昇格を検討する。
Touch / Pointer
- タッチデバイスではホバーが機能しないため、Hover Cardのコンテンツはタップ先のリンクページで表示する
- どうしてもモバイルでHover Cardを表示したい場合は、長押し(500ms)で表示し閉じるボタンを設ける
Contrast / Readability
- Hover Card内のテキストと背景のコントラストは4.5:1以上
- カードの影(
box-shadow)は背景に十分なコントラストをもたせてカードの境界を分かりやすくする
10. 実装メモ(Implementation Notes)
- shadcn/ui の
HoverCardは@radix-ui/react-hover-cardベースで、表示遅延(openDelay)・閉じる遅延(closeDelay)・カード上でのホバー維持・フォーカス対応・Floating UIの位置計算がすべて実装済み。新規実装よりHoverCardを使うのが最速 openDelay/closeDelayのデフォルト値は@radix-ui/react-hover-cardでは 700ms / 300ms。ユーザーの体感に合わせてopenDelay={400}/closeDelay={200}程度が自然- コンテンツをAPIから取得する場合、Hover Cardが開いた時にfetchを開始する(
onOpenChangeコールバック)。スケルトンUIを先に表示してデータが届いたら差し替えるとUXが向上する - カード内の「フォローボタン」など認証が必要なアクションは、未ログイン時に「ログインして続ける」へのリンクに切り替えるなど、状態に応じたコンテンツ出し分けを実装する
11. 関連リンク
- 関連するUIデザイン原則: 段階的開示 (Progressive Disclosure), フィードバック (Feedback)
- 用語集(定義): アクセシビリティ (Accessibility)
- 関連するUIコンポーネント(横): Tooltip(ツールチップ), Popover(ポップオーバー), Card(カード), Avatar(アバター)
12. まとめ
Hover Cardの設計で最重要なのは「ホバー遅延」と「カード上でのホバー維持」の2点です。迷ったら 4. 設計判断の核 に戻り、300〜500msの表示遅延・カード上でのタイマーキャンセル・フォーカス時の表示の3点を確認してください。shadcn/ui の HoverCard を使えば openDelay / closeDelay の設定だけでこれらは解決されます。Tooltip・Popover・Hover Cardの選択基準は「ホバーで開く・テキストのみ」→ Tooltip、「ホバーで開く・リッチなカード」→ Hover Card、「クリックで開く・インタラクティブ」→ Popoverというシンプルな分類で覚えてください。