布局组件
Accordion 手风琴
可展开/收起的内容面板,常用于 FAQ、设置项等场景。基于 Base UI Accordion 构建,支持单选和多选展开模式。
安装
bash
npx polyui add accordion基础
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionBasic() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full">
{faqItems.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger>{item.title}</AccordionTrigger>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}拆分
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionSplit() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full space-y-2">
{faqItems.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="bg-card rounded-md border-b-0 shadow-md data-open:shadow-lg"
>
<AccordionTrigger className="px-5">{item.title}</AccordionTrigger>
<AccordionContent className="text-muted-foreground px-5">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}带图标
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionWithIcon() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full">
{iconItems.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger>
<span className="flex items-center gap-4">
<item.icon className="text-muted-foreground size-4 shrink-0" />
<span>{item.title}</span>
</span>
</AccordionTrigger>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}Plus 图标
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships. For real-time updates, you can also use the tracking number provided in your shipping confirmation email.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
import { PlusIcon } from "lucide-react"
export function AccordionPlusIcon() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full" defaultValue={["item-1"]}>
{iconItems.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<div className="flex">
<AccordionTrigger
data-slot="accordion-trigger"
className="focus-visible:border-ring focus-visible:ring-ring/50 group/accordion-trigger flex flex-1 items-start justify-between gap-4 rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-expanded:[&>svg.plus-icon]:rotate-45"
>
<span className="flex items-center gap-4">
<item.icon className="size-4 shrink-0" />
<span>{item.title}</span>
</span>
<PlusIcon className="plus-icon text-muted-foreground pointer-events-none size-4 shrink-0 transition-transform duration-200" />
</AccordionTrigger>
</div>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}图标副标题
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships. For real-time updates, you can also use the tracking number provided in your shipping confirmation email.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
import { PlusIcon } from "lucide-react"
export function AccordionIconSubtitle() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full" defaultValue={["item-1"]}>
{iconItems.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<div className="flex">
<AccordionTrigger
data-slot="accordion-trigger"
className="focus-visible:border-ring focus-visible:ring-ring/50 group/accordion-trigger flex flex-1 items-center justify-between gap-4 rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-expanded:[&>svg.plus-icon]:rotate-45"
>
<span className="flex items-center gap-4">
<span
className="flex size-10 shrink-0 items-center justify-center rounded-full border"
aria-hidden="true"
>
<item.icon className="size-4" />
</span>
<span className="flex flex-col space-y-0.5">
<span>{item.title}</span>
<span className="text-muted-foreground font-normal">{item.subtitle}</span>
</span>
</span>
<PlusIcon className="plus-icon text-muted-foreground pointer-events-none size-4 shrink-0 transition-transform duration-200" />
</AccordionTrigger>
</div>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}高亮激活
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionActiveHighlight() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full" defaultValue={["item-1"]}>
{faqItems.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="data-open:border-amber-600 not-last:data-open:border-b-2 dark:data-open:border-amber-400"
>
<AccordionTrigger className="data-open:text-amber-600 dark:data-open:text-amber-400">
{item.title}
</AccordionTrigger>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}带头像
Richard Payne is a remarkable individual known for his exceptional skills and expertise in various fields.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
import { Avatar, AvatarImage, AvatarFallback } from "@polyui/react/avatar"
export function AccordionWithAvatar() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full" defaultValue={["item-1"]}>
{avatarItems.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger className="items-center hover:no-underline">
<span className="flex items-center gap-4">
<Avatar className="size-10 rounded-sm">
<AvatarImage src={item.src} alt={item.name} className="rounded-sm" />
<AvatarFallback className="rounded-sm text-xs">
{item.name.split(/\s/).reduce((acc, word) => acc + word.slice(0, 1), "")}
</AvatarFallback>
</Avatar>
<span className="flex flex-col space-y-0.5">
<span>{item.name}</span>
<span className="text-muted-foreground font-normal">{item.email}</span>
</span>
</span>
</AccordionTrigger>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}描边分隔
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships. For real-time updates, you can also use the tracking number provided in your shipping confirmation email.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionOutlineSeparated() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full space-y-2" defaultValue={["item-1"]}>
{faqItemsFull.map((item) => (
<AccordionItem key={item.value} value={item.value} className="rounded-md border!">
<AccordionTrigger className="px-5">{item.title}</AccordionTrigger>
<AccordionContent className="text-muted-foreground px-5">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}盒子样式
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships. For real-time updates, you can also use the tracking number provided in your shipping confirmation email.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionBox() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full rounded-md border" defaultValue={["item-1"]}>
{faqItemsFull.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger className="px-5">{item.title}</AccordionTrigger>
<AccordionContent className="text-muted-foreground px-5">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}标签页
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships. For real-time updates, you can also use the tracking number provided in your shipping confirmation email.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionTabs() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full" defaultValue={["item-1"]}>
{faqItemsFull.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="data-open:bg-accent rounded-md border-none px-5 transition-colors duration-200"
>
<AccordionTrigger>{item.title}</AccordionTrigger>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}描边标签页
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships. For real-time updates, you can also use the tracking number provided in your shipping confirmation email.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
import { PlusIcon } from "lucide-react"
export function AccordionTabsOutline() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full" defaultValue={["item-1"]}>
{faqItemsFull.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="data-open:border-border rounded-md border border-transparent px-5 transition-colors duration-200 data-open:border data-open:shadow-md"
>
<div className="flex">
<AccordionTrigger
data-slot="accordion-trigger"
className="focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-center justify-between gap-4 rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 aria-expanded:[&>svg.plus-icon]:rotate-45"
>
{item.title}
<PlusIcon className="plus-icon text-muted-foreground pointer-events-none size-4 shrink-0 transition-transform duration-200" />
</AccordionTrigger>
</div>
<AccordionContent className="text-muted-foreground">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}带媒体
You'll receive tracking information via email once your order ships.

tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionWithMedia() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full" defaultValue={["item-1"]}>
{mediaItems.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger>
<span className="flex items-center gap-4">
<item.icon className="size-4 shrink-0" />
<span>{item.title}</span>
</span>
</AccordionTrigger>
<AccordionContent className="space-y-4">
<p className="text-muted-foreground">{item.content}</p>
<img src={item.media} alt={item.title} className="w-full rounded-md" />
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}填充头部
You can track your order by logging into your account and visiting the "Orders" section. You'll receive tracking information via email once your order ships. For real-time updates, you can also use the tracking number provided in your shipping confirmation email.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
export function AccordionFilledHeader() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full space-y-2" defaultValue={["item-1"]}>
{faqItemsFull.map((item) => (
<AccordionItem key={item.value} value={item.value} className="rounded-md border!">
<AccordionTrigger className="bg-accent px-5 data-open:rounded-b-none">{item.title}</AccordionTrigger>
<AccordionContent className="text-muted-foreground px-5 pt-4">{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}多层级
You can track your order by logging into your account and visiting the "Orders" section.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@polyui/react/collapsible"
import { PlusIcon, ChevronDownIcon } from "lucide-react"
export function AccordionMultilevel() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full rounded-md border" defaultValue={["item-1"]}>
{multilevelItems.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="outline-none first:rounded-t-md last:rounded-b-md"
>
<div className="flex">
<AccordionTrigger
data-slot="accordion-trigger"
className="focus-visible:border-ring focus-visible:ring-ring/50 flex w-full flex-1 items-start justify-between gap-4 rounded-lg px-5 py-4 text-left text-sm font-medium transition-all outline-none hover:underline disabled:pointer-events-none disabled:opacity-50 aria-expanded:[&>svg.plus-icon]:rotate-45"
>
<span className="flex items-center gap-4">
<item.icon className="size-4 shrink-0" />
<span>{item.category}</span>
</span>
<PlusIcon className="plus-icon text-muted-foreground pointer-events-none size-4 shrink-0 transition-transform duration-200" />
</AccordionTrigger>
</div>
<AccordionContent className="pb-0">
{item.faqs.map((faq, i) => (
<Collapsible key={i} className="bg-accent border-t px-5" defaultOpen={i === 0}>
<CollapsibleTrigger className="focus-visible:ring-ring/50 flex w-full items-center gap-4 rounded-sm py-4 font-medium outline-none focus-visible:z-10 focus-visible:ring-[3px]">
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0" />
{faq.title}
</CollapsibleTrigger>
<CollapsibleContent className="text-muted-foreground overflow-hidden pb-4">
{faq.content}
</CollapsibleContent>
</Collapsible>
))}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}多层级 Plus
You can track your order by logging into your account and visiting the "Orders" section.
tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@polyui/react/accordion"
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "@polyui/react/collapsible"
import { PlusIcon } from "lucide-react"
export function AccordionMultilevelPlus() {
return (
<div className="flex flex-col gap-8 w-full max-w-lg">
<Accordion className="w-full rounded-md border" defaultValue={["item-1"]}>
{multilevelItems.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="outline-none first:rounded-t-md last:rounded-b-md"
>
<AccordionTrigger className="px-5 outline-none focus-visible:ring-0">{item.category}</AccordionTrigger>
<AccordionContent className="pb-0">
{item.faqs.map((faq, i) => (
<Collapsible key={i} className="bg-muted border-t px-8" defaultOpen={i === 0}>
<CollapsibleTrigger className="focus-visible:ring-ring/50 flex w-full items-center gap-4 rounded-sm py-4 font-medium outline-none focus-visible:z-10 focus-visible:ring-[3px] aria-expanded:[&>svg.plus-icon]:rotate-45">
<PlusIcon className="plus-icon text-muted-foreground pointer-events-none size-4 shrink-0 transition-transform duration-200" />
{faq.title}
</CollapsibleTrigger>
<CollapsibleContent className="text-muted-foreground overflow-hidden pb-4">
{faq.content}
</CollapsibleContent>
</Collapsible>
))}
</AccordionContent>
</AccordionItem>
))}
</Accordion>
</div>
)
}Props — Accordion
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
openMultiple | boolean | false | 是否允许多个面板同时展开 |
defaultValue | string | string[] | — | 非受控模式下默认展开的面板 value |
value | string | string[] | — | 受控模式下当前展开的面板 value |
onValueChange | (value: string | string[]) => void | — | 展开状态变化时的回调 |
className | string | — | 自定义样式类名 |
Props — AccordionItem
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value | string | — | 该面板的唯一标识,必填 |
disabled | boolean | false | 是否禁用该面板 |
className | string | — | 自定义样式类名 |