Frontend Lab
← 回到所有模式
PB03🪟 Overlay · 覆蓋層彈出

Popover

彈出層

難度 ★★★★★標籤 popover · floating · anchor3 min read

模式簡述

Popover:錨定在某個 element 旁的小面板。和 tooltip 的差別是 popover 可互動(有按鈕、輸入框)。

關閉|預設關閉

Claude Code Prompt

💬 Claude Code Prompt
參考:PB03 popover
組件:Popover.tsx

Popover:錨定在某個 element 旁的小面板。和 tooltip 的差別是 popover 可互動(有按鈕、輸入框)。

限制:
- 位置貼邊跑出視口
- 外部點擊沒關閉
- 箭頭三角形對不準

完整程式碼

Popover.tsx
"use client";
import { useEffect, useState } from "react";

type State = "closed" | "open";

export function Popover({ state = "open" }: { state?: State }) {
const [open, setOpen] = useState(state === "open");
useEffect(() => setOpen(state === "open"), [state]);

return (
  <div className="relative grid h-[260px] w-full max-w-md place-items-center">
    <div className="relative">
      <button
        onClick={() => setOpen((o) => !o)}
        className="rounded-md border border-border bg-background/50 px-3 py-1.5 font-mono text-xs hover:border-lab-accent"
      >
        設定 ▾
      </button>
      {open && (
        <div className="absolute left-1/2 top-full z-10 mt-2 w-56 -translate-x-1/2 rounded-lg border border-border bg-background p-3 shadow-xl animate-in fade-in zoom-in-95 duration-150">
          <div className="absolute -top-1.5 left-1/2 h-3 w-3 -translate-x-1/2 rotate-45 border-l border-t border-border bg-background" />
          <p className="mb-2 font-mono text-[10px] uppercase tracking-wider text-muted-foreground/70">
            偏好設定
          </p>
          <label className="flex items-center justify-between py-1 text-xs">
            <span>啟用通知</span>
            <input type="checkbox" defaultChecked className="accent-lab-accent" />
          </label>
          <label className="flex items-center justify-between py-1 text-xs">
            <span>自動儲存</span>
            <input type="checkbox" defaultChecked className="accent-lab-accent" />
          </label>
          <label className="flex items-center justify-between py-1 text-xs">
            <span>深色模式</span>
            <input type="checkbox" className="accent-lab-accent" />
          </label>
        </div>
      )}
    </div>
  </div>
);
}

何時用

  • ✅ 設定面板的快速調整
  • ✅ 顯示細節而不離開當前情境
  • ✅ 資訊密度中等(比 tooltip 多,比 modal 少)

何時別用

  • ❌ 內容超過半個螢幕(用 modal)
  • ❌ 純顯示提示(用 tooltip)
  • ❌ 需要使用者完成多步驟(用 dialog + stepper)

我踩過的坑

  1. 位置貼邊跑出視口:用 @floating-ui/react 算 flip + shift,別自己手算。

  2. 外部點擊沒關閉:要綁 mousedown 在 document,e.target.closest(popover) 判斷。

  3. 箭頭三角形對不準:用 Popper 或 floating-ui 內建的 arrow middleware。

相關模式

  • PB04
  • PB07

搜尋

按 ⌘K 隨時開啟