コンテンツにスキップ

ホバーカード

リンクの背後にあるコンテンツを、視覚的なユーザーがプレビューできるようにします。
Radix UI
vue
<script setup lang="ts">
import { ref } from 'vue'
import { HoverCardArrow, HoverCardContent, HoverCardPortal, HoverCardRoot, HoverCardTrigger } from 'radix-vue'

const hoverState = ref(false)
</script>

<template>
  <HoverCardRoot v-model:open="hoverState">
    <HoverCardTrigger
      class="inline-block cursor-pointer rounded-full shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] outline-none focus:shadow-[0_0_0_2px_white]"
      href="https://twitter.com/radix_ui"
      target="_blank"
      rel="noreferrer noopener"
    >
      <img
        class="block h-[45px] w-[45px] rounded-full"
        src="https://pbs.twimg.com/profile_images/1337055608613253126/r_eiMp2H_400x400.png"
        alt="Radix UI"
      >
    </HoverCardTrigger>
    <HoverCardPortal>
      <HoverCardContent
        class="data-[side=bottom]:animate-slideUpAndFade data-[side=right]:animate-slideLeftAndFade data-[side=left]:animate-slideRightAndFade data-[side=top]:animate-slideDownAndFade w-[300px] rounded-md bg-white p-5 shadow-[hsl(206_22%_7%_/_35%)_0px_10px_38px_-10px,hsl(206_22%_7%_/_20%)_0px_10px_20px_-15px] data-[state=open]:transition-all"
        :side-offset="5"
      >
        <div class="flex flex-col gap-[7px]">
          <img
            class="block h-[60px] w-[60px] rounded-full"
            src="https://pbs.twimg.com/profile_images/1337055608613253126/r_eiMp2H_400x400.png"
            alt="Radix UI"
          >
          <div class="flex flex-col gap-[15px]">
            <div>
              <div class="text-mauve12 m-0 text-[15px] font-medium leading-[1.5]">
                Radix
              </div>
              <div class="text-mauve10 m-0 text-[15px] leading-[1.5]">
                @radix_ui
              </div>
            </div>
            <div class="text-mauve12 m-0 text-[15px] leading-[1.5]">
              Components, icons, colors, and templates for building high-quality, accessible UI. Free and open-source.
            </div>
            <div class="flex gap-[15px]">
              <div class="flex gap-[5px]">
                <div class="text-mauve12 m-0 text-[15px] font-medium leading-[1.5]">
                  0
                </div>
                <div class="text-mauve10 m-0 text-[15px] leading-[1.5]">
                  Following
                </div>
              </div>
              <div class="flex gap-[5px]">
                <div class="text-mauve12 m-0 text-[15px] font-medium leading-[1.5]">
                  2,900
                </div>
                <div class="text-mauve10 m-0 text-[15px] leading-[1.5]">
                  Followers
                </div>
              </div>
            </div>
          </div>
        </div>

        <HoverCardArrow
          class="fill-white"
          :width="8"
        />
      </HoverCardContent>
    </HoverCardPortal>
  </HoverCardRoot>
</template>

機能

  • 制御あり、または制御なしにできます。
  • サイド、配置、オフセット、衝突処理をカスタマイズできます。
  • オプションで、指し示す矢印をレンダリングします。
  • カスタムの開閉遅延をサポートします。
  • スクリーンリーダーでは無視されます。

インストール

コマンドラインからコンポーネントをインストールします。

sh
$ npm add radix-vue

構造

すべてのパーツをインポートして、それらをまとめます。

vue
<script setup>
import { HoverCardArrow, HoverCardContent, HoverCardPortal, HoverCardRoot, HoverCardTrigger } from 'radix-vue'
</script>

<template>
  <HoverCardRoot>
    <HoverCardTrigger />
    <HoverCardPortal>
      <HoverCardContent>
        <HoverCardArrow />
      </HoverCardContent>
    </HoverCardPortal>
  </HoverCardRoot>
</template>

APIリファレンス

ルート

ホバーカードのすべてのパーツを含みます。

プロパティデフォルト
closeDelay
300
数値

マウスがトリガーまたはコンテンツから離れてからホバーカードが閉じるまでの時間。

defaultOpen
false
false

ホバーカードが最初にレンダリングされるときの開閉状態。開閉状態を制御する必要がない場合に使用します。

open
真偽値

ホバーカードの制御された開閉状態。v-model:openとしてバインドできます。

openDelay
700
数値

マウスがトリガーに入ってからホバーカードが開くまでの時間。

イベントペイロード
update:open
[value: 真偽値]

ホバーカードの開閉状態が変更されたときに呼び出されるイベントハンドラー。

スロット (デフォルト)ペイロード
open
真偽値

現在の開閉状態

トリガー

ホバーするとホバーカードを開くリンク。

プロパティデフォルト
as
'a'
AsTag | コンポーネント

このコンポーネントがレンダリングする要素またはコンポーネント。asChildで上書きできます。

asChild
真偽値

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

データ属性
[data-state]"open" | "closed"

ポータル

使用すると、コンテンツ部分をbodyにポータルします。

プロパティデフォルト
disabled
真偽値

テレポートを無効にして、コンポーネントをインラインでレンダリングします

reference

forceMount
真偽値

より多くの制御が必要な場合に、強制的にマウントするために使用します。Vueアニメーションライブラリでアニメーションを制御する場合に便利です。

to
文字列 | HTMLElement

Vueネイティブのテレポートコンポーネントのプロパティ:to

reference

コンテンツ

ホバーカードが開いたときにポップアウトするコンポーネント。

プロパティデフォルト
align
'start' | 'center' | 'end'

トリガーに対する優先的な配置。衝突が発生した場合は変更される可能性があります。

alignOffset
数値

startまたはendの配置オプションからのピクセル単位のオフセット。

arrowPadding
数値

矢印とコンテンツの端の間のパディング。コンテンツにborder-radiusがある場合、これが角からあふれるのを防ぎます。

as
'div'
AsTag | コンポーネント

このコンポーネントがレンダリングする要素またはコンポーネント。asChildで上書きできます。

asChild
真偽値

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

avoidCollisions
真偽値

trueの場合、境界の端との衝突を防ぐために、サイドと配置の優先順位を上書きします。

collisionBoundary
要素 | (要素 | null)[] | null

衝突境界として使用される要素。デフォルトではこれはビューポートですが、このチェックに含める追加の要素を提供できます。

collisionPadding
数値 | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>

衝突検出が発生する境界の端からのピクセル単位の距離。数値(すべての辺で同じ)または部分的なパディングオブジェクト(例:{ top: 20, left: 20 })を受け入れます。

forceMount
真偽値

より多くの制御が必要な場合に、強制的にマウントするために使用します。Vueアニメーションライブラリでアニメーションを制御する場合に便利です。

hideWhenDetached
真偽値

トリガーが完全に遮られたときにコンテンツを非表示にするかどうか。

prioritizePosition
真偽値

コンテンツをビューポート内に配置するように強制します。

参照要素と重複する可能性があり、望ましくない場合があります。

side
'top' | 'right' | 'bottom' | 'left'

開いたときにレンダリングするトリガーの優先サイド。衝突が発生し、avoidCollisionsが有効になっている場合は反転します。

sideOffset
数値

トリガーからのピクセル単位の距離。

sticky
'partial' | 'always'

配置軸のスティッキー動作。partialは、トリガーが少なくとも部分的に境界内にある限り、コンテンツを境界内に保持し、「always」はコンテンツを常に境界内に保持します。

updatePositionStrategy
'always' | 'optimized'

すべてのアニメーションフレームでフローティング要素の位置を更新する戦略。

イベントペイロード
escapeKeyDown
[event: KeyboardEvent]

エスケープキーが押されたときに呼び出されるイベントハンドラー。阻止できます。

focusOutside
[event: FocusOutsideEvent]

フォーカスがDismissableLayerの外に移動したときに呼び出されるイベントハンドラー。阻止できます。

interactOutside
[event: PointerDownOutsideEvent | FocusOutsideEvent]

DismissableLayerの外部でインタラクションが発生したときに呼び出されるイベントハンドラー。具体的には、pointerdownイベントが外部で発生した場合、またはフォーカスが外部に移動した場合。阻止できます。

pointerDownOutside
[event: PointerDownOutsideEvent]

pointerdownイベントがDismissableLayerの外部で発生したときに呼び出されるイベントハンドラー。阻止できます。

データ属性
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
CSS変数説明
--radix-hover-card-content-transform-origin
コンテンツと矢印の位置/オフセットから計算されたtransform-origin
--radix-hover-card-content-available-width
トリガーと境界の端の間の残りの幅
--radix-hover-card-content-available-height
トリガーと境界の端の間の残りの高さ
--radix-hover-card-trigger-width
トリガーの幅
--radix-hover-card-trigger-height
トリガーの高さ

矢印

ホバーカードと一緒にレンダリングするオプションの矢印要素。これは、トリガーをHoverCardContentと視覚的にリンクするのに役立ちます。HoverCardContent内でレンダリングする必要があります。

プロパティデフォルト
as
'svg'
AsTag | コンポーネント

このコンポーネントがレンダリングする要素またはコンポーネント。asChildで上書きできます。

asChild
真偽値

子として渡された要素のデフォルトのレンダリング要素を変更し、それらのプロパティと動作をマージします。

詳細については、コンポジションガイドをお読みください。

height
5
数値

ピクセル単位の矢印の高さ。

width
10
数値

ピクセル単位の矢印の幅。

すぐに表示

ホバーカードが開くまでの時間を制御するには、openDelayプロパティを使用します。

vue
<script setup>
import {
  HoverCardArrow,
  HoverCardContent,
  HoverCardPortal,
  HoverCardRoot,
  HoverCardTrigger,
} from 'radix-vue'
</script>

<template>
  <HoverCardRoot :open-delay="0">
    <HoverCardTrigger></HoverCardTrigger>
    <HoverCardContent></HoverCardContent>
  </HoverCardRoot>
</template>

コンテンツサイズを制約する

コンテンツの幅をトリガーの幅と一致するように制約したい場合があります。また、高さをビューポートを超えないように制約したい場合があります。

これをサポートするために、--radix-hover-card-trigger-width--radix-hover-card-content-available-heightなどのいくつかのCSSカスタムプロパティを公開しています。それらを使用してコンテンツの寸法を制約します。

vue
// index.vue
<script setup>
import { HoverCardArrow, HoverCardContent, HoverCardPortal, HoverCardRoot, HoverCardTrigger } from 'radix-vue'
</script>

<template>
  <HoverCardRoot>
    <HoverCardTrigger></HoverCardTrigger>
    <HoverCardPortal>
      <HoverCardContent
        class="HoverCardContent"
        :side-offset="5"
      >

      </HoverCardContent>
    </HoverCardPortal>
  </HoverCardRoot>
</template>
css
/* styles.css */
.HoverCardContent {
  width: var(--radix-hover-card-trigger-width);
  max-height: var(--radix-hover-card-content-available-height);
}

原点認識アニメーション

CSSカスタムプロパティ--radix-hover-card-content-transform-originを公開しています。sidesideOffsetalignalignOffset、および衝突に基づいて計算された原点からコンテンツをアニメーション化するために使用します。

vue
// index.vue
<script setup>
import { HoverCardArrow, HoverCardContent, HoverCardPortal, HoverCardRoot, HoverCardTrigger } from 'radix-vue'
</script>

<template>
  <HoverCardRoot>
    <HoverCardTrigger></HoverCardTrigger>
    <HoverCardContent class="HoverCardContent">

    </HoverCardContent>
  </HoverCardRoot>
</template>
css
/* styles.css */
.HoverCardContent {
  transform-origin: var(--radix-hover-card-content-transform-origin);
  animation: scaleIn 0.5s ease-out;
}

@keyframes scaleIn {
  from {
    opacity: 0;
    transform: scale(0);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

衝突認識アニメーション

data-sideおよびdata-align属性を公開しています。それらの値は、衝突を反映するために実行時に変更されます。それらを使用して、衝突と方向を認識するアニメーションを作成します。

vue
// index.vue
<script setup>
import { HoverCardArrow, HoverCardContent, HoverCardPortal, HoverCardRoot, HoverCardTrigger } from 'radix-vue'
</script>

<template>
  <HoverCardRoot>
    <HoverCardTrigger></HoverCardTrigger>
    <HoverCardContent class="HoverCardContent">

    </HoverCardContent>
  </HoverCardRoot>
</template>
css
/* styles.css */
.HoverCardContent {
  animation-duration: 0.6s;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.HoverCardContent[data-side="top"] {
  animation-name: slideUp;
}
.HoverCardContent[data-side="bottom"] {
  animation-name: slideDown;
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slideDown {
  from {
    opacity: 0;
    transform: translateY(-10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

アクセシビリティ

ホバーカードは視覚的なユーザーのみを対象としており、コンテンツはキーボードユーザーにはアクセスできません。

キーボード操作

キー説明
Tab
ホバーカードを開閉します。
Enter
ホバーカードのリンクを開きます