PB09▸🪟 Overlay · 覆蓋層▸預覽
Hover Card
懸停卡片
難度 ★★★★★標籤 hover · card · profile3 min read
模式簡述
Hover Card:類似 link preview,但通常用在「人」或「實體」的快速資訊卡:頭像、@提及、tag。
E
Ephraim
@ephraim · 接案工程師
專做品牌官網與後台介面,主玩 Next.js + Cloudflare。
128 追蹤者42 專案
Claude Code Prompt
參考:PB09 hover-card 組件:HoverCard.tsx Hover Card:類似 link preview,但通常用在「人」或「實體」的快速資訊卡:頭像、@提及、tag。 限制: - 沒做 600ms 緩衝 - 卡片內容太多 - 卡片離開 trigger 太遠
完整程式碼
"use client";
import { useEffect, useState } from "react";
type State = "hover" | "loading";
export function HoverCard({ state = "hover" }: { state?: State }) {
const [hover, setHover] = useState(true);
useEffect(() => setHover(true), [state]);
const loading = state === "loading";
return (
<div className="grid h-[280px] w-full max-w-md place-items-center">
<div className="relative">
<button
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
className="inline-flex items-center gap-2 rounded-md border border-border bg-background/50 px-3 py-1.5 text-xs hover:border-lab-accent"
>
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-lab-accent/20 font-mono text-[10px] text-lab-accent">
E
</span>
@ephraim
</button>
{hover && (
<div className="absolute left-1/2 top-full z-10 mt-2 w-64 -translate-x-1/2 rounded-lg border border-border bg-background p-3 shadow-xl animate-in fade-in zoom-in-95 duration-150">
{loading ? (
<div className="space-y-2">
<div className="flex gap-2">
<div className="h-10 w-10 animate-pulse rounded-full bg-muted" />
<div className="flex-1 space-y-1.5">
<div className="h-3 w-20 animate-pulse rounded bg-muted" />
<div className="h-2.5 w-28 animate-pulse rounded bg-muted" />
</div>
</div>
<div className="h-2.5 w-full animate-pulse rounded bg-muted" />
<div className="h-2.5 w-2/3 animate-pulse rounded bg-muted" />
</div>
) : (
<>
<div className="flex items-start gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-lab-accent/20 font-mono text-sm text-lab-accent">
E
</div>
<div>
<p className="text-sm font-medium">Ephraim</p>
<p className="font-mono text-[11px] text-muted-foreground">@ephraim · 接案工程師</p>
</div>
</div>
<p
className="mt-2.5 text-xs text-muted-foreground"
style={{ fontFamily: "var(--font-zh)" }}
>
專做品牌官網與後台介面,主玩 Next.js + Cloudflare。
</p>
<div className="mt-2.5 flex gap-3 font-mono text-[11px] text-muted-foreground">
<span>
<span className="text-foreground">128</span> 追蹤者
</span>
<span>
<span className="text-foreground">42</span> 專案
</span>
</div>
</>
)}
</div>
)}
</div>
</div>
);
}何時用
- ✅ @username 提及的個人卡片
- ✅ tag 的描述與相關項目
- ✅ GitHub 風格的 commit author 預覽
何時別用
- ❌ 手機優先的介面
- ❌ 卡片內有複雜互動(用 popover)
- ❌ 純文字提示(用 tooltip)
我踩過的坑
-
沒做 600ms 緩衝:滑鼠移出又移回不該關閉。用 framer-motion 加 delay。
-
卡片內容太多:超過 3-4 行就太擠,改用 popover 或新分頁。
-
卡片離開 trigger 太遠:使用者要把滑鼠移過空白才到卡片,途中關了。要做 safe triangle。
相關模式
- PB04
- PB08