Hover card
リンクにホバーまたはフォーカスすると開くプレビューカードです。視覚で閲覧するユーザーがさっと確認できる内容向けです。
pnpm dlx shadcn@latest add https://hextaui.com/r/hover-card.jsonコンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。
まだ追加していない場合は、グローバルCSSにテーマトークンを追加してください。
依存関係をインストールします。
pnpm add @base-ui/react cn次のコードをコピーしてプロジェクトに貼り付けてください。
components/ui/hover-card.tsx lib/motion.ts インポートパスは、お使いのプロジェクト構成に合わせて更新してください。
ホバーカードはプレビューであり、メニューやダイアログではありません。トリガーは通常のリンクのままなので、カード内のすべての内容は、リンク先のページにも存在する必要があります。
側
<HoverCardContent /> に side と align を設定します。inline-end のような論理的な側は読む方向に従い、カードは画面から出そうなときに反転またはシフトします。
遅延
トリガーの delay と closeDelay は、カードが開くまでにポインターが静止しなければならない時間と、離れた後に残る時間を設定します。デフォルトの 600ms は、ポインターがページを横切る際にカードが一瞬開くのを防ぎます。
インラインリンク
render を使うと、文中のリンクを含め、任意のリンクをトリガーにできます。リンクが 2 行に折り返された場合、カードはホバーした行にアンカーされます。
インタラクティブなコンテンツ
ポインターをリンクからカードに移動してもカードは開いたままなので、内側のリンクやボタンをクリックできます。両者の間の経路には余裕があるため、斜めに動かしても閉じません。
共有カード
1 つのカードが複数のリンクに対応します。createHoverCardHandle でハンドルを作成し、各トリガーに payload を与え、カード内でそれを読み取ります。名前の間を移動すると、カードは閉じて開き直すのではなく、新しいリンクへ滑らかに移動します。古いコンテンツは動いた方向へスライドアウトし、新しいコンテンツがスライドインし、高さは両者の間でイージングします。
矢印
arrow は、カードの枠線と継ぎ目なくつながる矢印を追加します。側のオフセットは矢印の分だけ広がり、カードが反転すると矢印も追従します。
読み込み中のコンテンツ
onOpenChange で取得を開始し、データが届くまでスケルトンを表示します。コンテンツが変わると、カードは跳ねずに新しい高さへイージングします。
制御
open と onOpenChange を渡します。第 2 引数は、trigger-hover、trigger-focus、escape-key など、変更の理由を示します。
長いコンテンツ
区切りのないテキストはカード内で折り返され、トリガーの横の空間より高いカードは、画面から出ずにスクロールします。
右から左
カードはトリガーの方向を読み取るため、論理的な側と揃え位置は反転し、スケールアニメーションは正しい角から拡大します。
| キー | アクション |
|---|---|
| Tab | トリガーにフォーカスすると、ホバーと同じ遅延の後にカードが開きます。フォーカスが移動すると閉じます。 |
| Enter | 他のリンクと同様に、リンク先へ移動します。 |
| Esc | カードを閉じます。 |
- カードは、マウスとキーボードを使う晴眼のユーザー向けの視覚的な追加要素です。スクリーンリーダーにはリンクだけが読み上げられるため、通り過ぎるすべてのリンクでプレビューを読まされることはありません。
- ホバーのないタッチスクリーンでは、何も開きません。タップするとリンク先に移動するため、リンク先にも同じ情報が含まれている必要があります。
- フォーカスがカード内に移動することはありません。キーボードで到達できる必要のあるコントロールが必要な場合は、代わりにポップオーバーを使ってください。
- モーションの低減が有効な場合、カードは拡大縮小せずにフェードし、共有カードはリンク間を滑らかに移動せずにジャンプします。
Base UI の preview card をベースにしています。各パーツは、ラップしているプリミティブの props を受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
onOpenChangedetails.reason は、trigger-hover、trigger-focus、trigger-press、outside-press、escape-key、imperative-action、none のいずれかです。 | (open: boolean, details) => void | – |
onOpenChangeComplete開閉アニメーションの終了後に呼ばれます。 | (open: boolean) => void | – |
handleルートの外側にレンダリングされたトリガーを接続します。 | HoverCardHandle<Payload> | – |
childrenカードを開いたトリガーの payload を読み取るには、関数形式を使います。 | ReactNode | ({ payload }) => ReactNode | – |
actionsRef | RefObject<{ close, unmount }> | – |
| プロパティ | 型 | デフォルト |
|---|---|---|
href | string | – |
delayホバーまたはフォーカスしてからカードが開くまでのミリ秒。 | number | 600 |
closeDelay離れた後、カードが開いたままでいるミリ秒。 | number | 300 |
handle | HoverCardHandle<Payload> | – |
payloadこのトリガーがカードを開いたときに、カードに渡されます。 | Payload | – |
render<Button variant="link" /> やルーターのリンクなど、独自のリンクをレンダリングします。 | ReactElement | (props, state) => ReactElement | <a> |
| 属性 | 説明 |
|---|---|
data-slot="hover-card-trigger" | CSSでトリガーを指定します。 |
data-popup-open | このトリガーのカードが開いている間、付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
align | "start" | "center" | "end" | "center" |
arrowトリガーの方向を指す矢印を表示します。 | boolean | false |
sideOffset | number | OffsetFunction | 6, or 10 with arrow |
alignOffset | number | OffsetFunction | 0 |
collisionPaddingカードとビューポートの端の間に確保される空間。 | number | Rect | 8 |
collisionAvoidance衝突時に、カードが反転するか、シフトするか、何もしないか。 | CollisionAvoidance | – |
sticky | boolean | false |
anchorトリガー以外のものを基準に配置します。 | Element | RefObject | VirtualElement | – |
positionMethod | "absolute" | "fixed" | "absolute" |
disableAnchorTracking | boolean | false |
portalPropscontainer など、ポータル用の props。 | HoverCardPortalProps | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| 属性 | 説明 |
|---|---|
data-slot="hover-card-content" | CSSでカードを指定します。 |
data-open | カードが開いている間、付与されます。 |
data-starting-style | カードが表示アニメーションをしている間、付与されます。 |
data-ending-style | カードが非表示アニメーションをしている間、付与されます。 |
data-instant | キーボードフォーカスでカードが開いた場合は focus、Escape または外側の押下で閉じた場合は dismiss。設定されている間、終了アニメーションはスキップされます。 |
data-side | 衝突の処理後にカードが決まった側。 |
data-align | 最終的に決まった揃え位置。 |
--transform-origin | トリガーの隣にある、スケールアニメーションの拡大の起点。 |
--available-width | トリガーの横に残っている空間。カードがそれを超えて広がることはありません。 |
--available-height | 上または下に残っている空間。それより高いコンテンツはスクロールします。 |
| Positioner の属性 | 説明 |
|---|---|
data-slot="hover-card-positioner" | 動く要素。共有カードがリンクを切り替えるときに滑らかに移動します。 |
data-anchor-hidden | トリガーがスクロールで見えなくなったときに付与されます。 |
| 内部パーツ | 説明 |
|---|---|
data-slot="hover-card-viewport" | コンテンツを包みます。共有カードがリンクを切り替える間、data-activation-direction を持ちます。 |
data-slot="hover-card-body" | あなたのコンテンツ。変化すると高さがイージングします。 |
data-slot="hover-card-arrow" | ポインター。その端を示す data-side を持ちます。 |
--popup-height | リンク間でカードのサイズが変わっている間、カードに設定されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
container | HTMLElement | ShadowRoot | RefObject | null | document.body |
keepMounted | boolean | false |
分離されたトリガー用のハンドルを返します。その open(triggerId) と close() メソッドでイベントハンドラーからカードを制御でき、isOpen で状態を読み取れます。payload に型を付けるには、型引数を渡します。
- Motionすべてのコンポーネントがアニメーションに使うイージングカーブ、継続時間、モーション軽減のチェックと、サイズのモーフィングやスライドするハイライト用のフックです。
- Alert dialog破壊的または重要な操作のための確認ダイアログです。非同期処理を待ち、スマートフォンではボトムシートになります。
- Commandインラインまたは⌘Kパレットとして使える、検索可能な操作リストです。ページ、ショートカット、一致箇所のハイライトに対応します。
- Context menu右クリックまたは長押しで開く操作メニューです。サブメニュー、チェックボックス項目、ラジオ項目に対応し、タッチでは長押しのフィードバックを返します。
- Dialogフォームや集中して行う作業のための、ページ上のウィンドウです。固定のヘッダーとフッター、入れ子に対応し、スマートフォンではスワイプできるボトムシートになります。
- Drawer任意の端からスライドインし、指に追従するパネルです。スナップポイント、実際に使えるハンドル、重なっていく入れ子のドロワーに対応します。
使用しているブロック
Hover card の上に構築されるブロック。