Frontend Lab
← 回到所有模式
PG03📐 Layout · 版型FAQ

FAQ

常見問題

難度 ★★★★標籤 faq · accordion · marketing4 min read

模式簡述

FAQ:常見問題折疊面板。marketing site 的轉換工具,回答銷售前的疑慮。問題要寫得像使用者會問的口吻。

免費版限個人專案,Pro 與 Team 版皆可商業使用,且不需署名。

全收合|FAQ 預設

Claude Code Prompt

💬 Claude Code Prompt
參考:PG03 faq
組件:FAQ.tsx

FAQ:常見問題折疊面板。marketing site 的轉換工具,回答銷售前的疑慮。問題要寫得像使用者會問的口吻。

限制:
- 問題寫得像 FAQ
- 所有問題默認全展開
- 沒有「還沒解答?聯絡我們」

完整程式碼

FAQ.tsx
"use client";
import { useEffect, useState } from "react";
import { ChevronDown } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";

type State = "collapsed" | "single-open" | "all-open";

const FAQS = [
{ q: "可以商用嗎?", a: "免費版限個人專案,Pro 與 Team 版皆可商業使用,且不需署名。" },
{ q: "如何取消訂閱?", a: "前往設定 → 訂閱 → 取消,當期結束後自動轉為免費版,不會被扣款。" },
{ q: "支援哪些框架?", a: "目前主要支援 React + Next.js,Vue 與 Svelte 版本規劃中。" },
{ q: "有 Figma 檔嗎?", a: "Pro 與 Team 用戶可下載對應 Figma Kit,設計變數已綁定 Tailwind tokens。" },
];

export function FAQ({ state = "single-open" }: { state?: State }) {
const [open, setOpen] = useState<Set<number>>(new Set([0]));

useEffect(() => {
  if (state === "collapsed") setOpen(new Set());
  else if (state === "all-open") setOpen(new Set([0, 1, 2, 3]));
  else setOpen(new Set([0]));
}, [state]);

const toggle = (i: number) =>
  setOpen((prev) => {
    const next = new Set(prev);
    next.has(i) ? next.delete(i) : next.add(i);
    return next;
  });

return (
  <div className="w-full max-w-xl">
    <div className="divide-y divide-border rounded-lg border border-border">
      {FAQS.map((f, i) => {
        const isOpen = open.has(i);
        return (
          <div key={i}>
            <button
              onClick={() => toggle(i)}
              className="flex w-full items-center justify-between gap-3 px-4 py-3 text-left text-sm hover:bg-muted/30"
            >
              <span>{f.q}</span>
              <ChevronDown
                className={`h-3.5 w-3.5 shrink-0 text-muted-foreground transition-transform ${isOpen ? "rotate-180" : ""}`}
              />
            </button>
            <AnimatePresence initial={false}>
              {isOpen && (
                <motion.div
                  initial={{ height: 0, opacity: 0 }}
                  animate={{ height: "auto", opacity: 1 }}
                  exit={{ height: 0, opacity: 0 }}
                  transition={{ duration: 0.2, ease: "easeOut" }}
                  className="overflow-hidden"
                >
                  <p className="px-4 pb-3 text-xs text-muted-foreground">{f.a}</p>
                </motion.div>
              )}
            </AnimatePresence>
          </div>
        );
      })}
    </div>
  </div>
);
}

何時用

  • ✅ 定價頁、產品頁的最後一段
  • ✅ support 站的快速答疑
  • ✅ 新功能上線後的釋疑

何時別用

  • ❌ 問題超過 20 個(要分類)
  • ❌ 答案需要圖文步驟(用 docs)
  • ❌ 問題很重要使用者必看(直接寫在頁面上)

我踩過的坑

  1. 問題寫得像 FAQ:使用者一看就不點。改成口語「我可以取消嗎?」

  2. 所有問題默認全展開:頁面變很長。預設折疊或只展開第一個。

  3. 沒有「還沒解答?聯絡我們」:使用者沒找到答案就跳走。最後加 contact CTA。

相關模式

  • PA02

搜尋

按 ⌘K 隨時開啟