Frontend Lab
← 回到所有模式
PB12🪟 Overlay · 覆蓋層對話框

Action Sheet (iOS)

iOS 動作清單

難度 ★★★★★標籤 iOS · 底部 · apple3 min read

模式簡述

Action Sheet:iOS 風格從底部彈出的選項清單。手指拇指可達區,破壞性動作標紅,最下方有「取消」。

關閉|預設關閉

Claude Code Prompt

💬 Claude Code Prompt
參考:PB12 action-sheet
組件:ActionSheet.tsx

Action Sheet:iOS 風格從底部彈出的選項清單。手指拇指可達區,破壞性動作標紅,最下方有「取消」。

限制:
- 沒在頂部加 grab handle
- 取消按鈕沒和選項分開
- 破壞性動作沒紅字

完整程式碼

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

type State = "closed" | "open" | "destructive";

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

return (
  <div className="relative h-[340px] w-full max-w-sm overflow-hidden rounded-2xl border border-border bg-background/30">
    <div className="grid h-full place-items-center">
      <button
        onClick={() => setOpen(true)}
        className="rounded-md border border-border bg-background/50 px-3 py-1.5 font-mono text-xs hover:border-lab-accent"
      >
        開啟 Action Sheet
      </button>
    </div>
    {open && (
      <>
        <div
          onClick={() => setOpen(false)}
          className="absolute inset-0 bg-black/40 animate-in fade-in duration-200"
        />
        <div className="absolute inset-x-2 bottom-2 space-y-2 animate-in slide-in-from-bottom duration-300">
          <div className="overflow-hidden rounded-2xl bg-background/95 backdrop-blur-xl">
            <p className="px-4 py-3 text-center text-[11px] text-muted-foreground">
              {destructive ? "刪除此項目嗎?" : "選擇操作"}
            </p>
            {destructive && (
              <button className="flex w-full items-center justify-center border-t border-border/40 px-4 py-3 text-base font-medium text-red-500 hover:bg-red-500/5">
                刪除
              </button>
            )}
            <button className="flex w-full items-center justify-center border-t border-border/40 px-4 py-3 text-base text-lab-accent hover:bg-lab-accent/5">
              {destructive ? "保留並隱藏" : "拍照"}
            </button>
            <button className="flex w-full items-center justify-center border-t border-border/40 px-4 py-3 text-base text-lab-accent hover:bg-lab-accent/5">
              {destructive ? "回報問題" : "從相簿選取"}
            </button>
          </div>
          <button
            onClick={() => setOpen(false)}
            className="w-full rounded-2xl bg-background/95 px-4 py-3 text-base font-semibold text-lab-accent backdrop-blur-xl hover:bg-background"
          >
            取消
          </button>
        </div>
      </>
    )}
  </div>
);
}

何時用

  • ✅ 手機端的多選項操作(分享、儲存、刪除)
  • ✅ 想營造原生 app 質感的 web 介面
  • ✅ 選項 3-7 個之間(多了就要分組或滾動)

何時別用

  • ❌ 桌面端(很違和,請改 dropdown)
  • ❌ 選項超過 8 個(會超出螢幕)
  • ❌ 需要輸入文字(這時候是 modal)

我踩過的坑

  1. 沒在頂部加 grab handle:iOS 規範會有一條 36x5px 的灰色把手,視覺暗示可拖。

  2. 取消按鈕沒和選項分開:應該空一格背景色,視覺上明確分組。

  3. 破壞性動作沒紅字:刪除、登出要用 system red (#FF3B30) 警告。

相關模式

  • PB01
  • PB02

搜尋

按 ⌘K 隨時開啟