Accordion
Disclosure rows machined into one housing — the open panel recesses into the chassis with a sprung height transition.
@emboss/accordion
Each channel delivers 48V phantom power, switchable per strip.
Installation
pnpm dlx shadcn@latest add @emboss/accordionUsage
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
export function Example() {
return (
<Accordion>
<AccordionItem value="power">
<AccordionTrigger>Power</AccordionTrigger>
<AccordionContent>48V phantom power per channel.</AccordionContent>
</AccordionItem>
</Accordion>
);
}API reference
Accordion
The housing. Pass an array value since multiple panels may open.
| Prop | Type | Default | Description |
|---|---|---|---|
| value / defaultValue / onValueChange | string[] / string[] / (value) => void | — | Controlled and uncontrolled open panels. |
| multiple | boolean | false | Allow several panels open at once. |
AccordionItem / AccordionTrigger / AccordionContent
One row: its value, the flush trigger, and the recessed panel.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | — | Identifies the item (AccordionItem). |
Keyboard
| Keys | Action |
|---|---|
| ArrowDownArrowUp | Moves focus between triggers. |
| Enter | Toggles the focused panel. |
| Space | Toggles the focused panel. |
Source
View source — accordion.tsxHide source — accordion.tsx
"use client";
import { Accordion as BaseAccordion } from "@base-ui/react/accordion";
import { ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
/**
* Disclosure rows machined into one housing. Closed items sit flush; the
* open item's panel recesses into the chassis as if a service hatch opened.
*
* @example
* <Accordion>
* <AccordionItem value="power">
* <AccordionTrigger>Power</AccordionTrigger>
* <AccordionContent>48V phantom power is delivered per channel.</AccordionContent>
* </AccordionItem>
* </Accordion>
*/
function Accordion({
className,
...props
}: React.ComponentProps<typeof BaseAccordion.Root>) {
return (
<BaseAccordion.Root
data-slot="accordion"
className={cn(
"w-full divide-y divide-edge-line rounded-md bg-surface-1 shadow-flush",
className,
)}
{...props}
/>
);
}
function AccordionItem({
className,
...props
}: React.ComponentProps<typeof BaseAccordion.Item>) {
return (
<BaseAccordion.Item
data-slot="accordion-item"
className={cn("group", className)}
{...props}
/>
);
}
function AccordionTrigger({
className,
children,
...props
}: React.ComponentProps<typeof BaseAccordion.Trigger>) {
return (
<BaseAccordion.Header className="flex">
<BaseAccordion.Trigger
data-slot="accordion-trigger"
className={cn(
"flex flex-1 cursor-pointer items-center justify-between gap-3 px-4 py-3 text-left text-sm font-medium text-ink focus-ring transition-[background-color] hover:bg-surface-2",
className,
)}
{...props}
>
{children}
<ChevronDown
aria-hidden
className="size-4 shrink-0 text-ink-faint transition-transform duration-(--duration-settle) ease-(--ease-settle) group-has-data-[panel-open]:rotate-180"
/>
</BaseAccordion.Trigger>
</BaseAccordion.Header>
);
}
function AccordionContent({
className,
children,
...props
}: React.ComponentProps<typeof BaseAccordion.Panel>) {
return (
<BaseAccordion.Panel
data-slot="accordion-content"
className={cn(
"h-(--accordion-panel-height) overflow-hidden bg-well text-sm text-ink-muted shadow-deboss-1 transition-[height] duration-(--duration-settle) ease-(--ease-settle) data-ending-style:h-0 data-starting-style:h-0",
className,
)}
{...props}
>
<div className="px-4 py-3">{children}</div>
</BaseAccordion.Panel>
);
}
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };