覆蓋層與回饋

Accordion

帶彈跳過渡的動畫手風琴/FAQ 展開,支援單開與多開。

以 spring 物理模型驅動高度展開,收尾自帶回彈;內容同步做輕微上滑,層次分明。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add accordion

還沒有專案,或安裝遇到問題?看快速開始 →

Accordion 是用 React、Motion 與 Tailwind CSS 做的手風琴(摺疊面板、collapse)元件,常用來做 FAQ 常見問題;每一列用 items 陣列描述,可設定單開或多開。

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

編輯中的呼叫預設屬性
<Accordion/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

適用情境

  • 產品頁、定價頁底部的常見問題
  • 說明中心文章裡的步驟或補充說明
  • 設定頁中把進階選項收起來的分組
  • 商品頁的規格、運送與退換貨資訊
  • 不適合:需要搜尋過濾與分類籤的完整 FAQ 區塊,可直接用 FAQ 手風琴區塊

安裝

npx webberui@latest add https://webberui.com/r/accordion.json

或在 components.json 設定 registries 後,改用 @webberui/accordion 安裝。

使用

import { Accordion } from "@/components/ui/accordion";

<Accordion
  defaultValue="a"
  items={[
    { value: "a", title: "第一題", content: "第一題的答案。" },
    { value: "b", title: "第二題", content: "第二題的答案。" },
  ]}
/>;

多開模式傳 multiple,defaultValue 可給字串陣列:

<Accordion multiple defaultValue={["a", "b"]} items={items} />

範例

在 Next.js App Router 的 FAQ 頁面

Accordion 是 client component,可以直接放在 Server Component 頁面裡,把伺服器端取得的文字資料轉成 items。

// app/faq/page.tsx(Server Component)
import { Accordion } from "@/components/ui/accordion";
import { getFaqs } from "@/lib/faqs";

export default async function FaqPage() {
  const faqs = await getFaqs();

  return (
    <Accordion
      defaultValue={faqs[0]?.id}
      items={faqs.map((faq) => ({
        value: faq.id,
        title: faq.question,
        content: faq.answer,
      }))}
    />
  );
}

內容放連結與清單

title 與 content 都接受 React 節點,可以放連結、清單或其他元件。

<Accordion
  items={[
    {
      value: "refund",
      title: "可以退款嗎?",
      content: (
        <>
          訂單成立後 7 天內可申請退款,請參考
          <a href="/refund-policy" className="underline">退款政策</a>。
        </>
      ),
    },
    {
      value: "invoice",
      title: "發票怎麼開立?",
      content: (
        <ul className="list-disc pl-5">
          <li>個人:電子發票寄送至註冊信箱</li>
          <li>公司:結帳時填寫統一編號</li>
        </ul>
      ),
    },
  ]}
/>

多開、不帶彈跳的設定面板

設定類介面通常希望動畫安靜一點,用 bounce={false} 改成平順淡入,並以 className 調整外框。

<Accordion
  multiple
  bounce={false}
  className="rounded-none border-x-0"
  items={[
    { value: "notify", title: "通知", content: <NotificationSettings /> },
    { value: "privacy", title: "隱私", content: <PrivacySettings /> },
  ]}
/>

Props

Prop型別預設值說明
itemsAccordionItemData[]—每一列的資料,含 value、title、content
multiplebooleanfalse允許同時展開多列
defaultValuestring | string[]—預設展開的 value
bouncebooleantrue過渡是否附帶彈跳,關閉則用平順淡入
classNamestring—透傳到最外層容器

AccordionItemData 欄位:value(唯一識別)、title(ReactNode)、content(ReactNode)。

可及性

  • trigger 使用原生 button,帶 aria-expanded 與 aria-controls;內容區為 region 並以 aria-labelledby 指回 trigger
  • 開啟系統「減少動態效果」時,退化為短促平順淡入,不做高度彈跳

常見問題

可以在 Next.js App Router 使用嗎?

可以。元件檔案開頭已有 "use client",在 Server Component 頁面中照常 import 即可。「減少動態效果」的判斷在掛載後才套用,首次渲染與 SSR 輸出一致。

收合的內容會出現在 HTML 裡嗎?

不會。只有展開中的列會渲染內容區,收合時內容會從 DOM 移除。如果希望某幾題在頁面載入時就輸出到 HTML,可以把它們放進 defaultValue。

可以用程式控制展開哪一列嗎?

目前只支援非受控模式,defaultValue 只在第一次渲染時讀取。需要重設展開狀態時,可以改變元件的 key 讓它重新掛載。

怎麼關掉彈跳動畫?

設定 bounce={false} 會改用約 0.2 秒的平順淡入;使用者系統開啟「減少動態效果」時也會自動改用這個過渡。

鍵盤與螢幕閱讀器支援嗎?

每列標題是包在 h3 裡的原生 button,帶 aria-expanded 與 aria-controls,可用 Tab 移動、Enter 或 Space 切換;內容區為 role="region",以 aria-labelledby 指回標題。