Skip to content

Accordion

A vertically stacked set of interactive headings that each reveal a section of content.

Code
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@falcon/ui-kit";
export function Example() {
return (
<Accordion defaultValue={["delivery"]} className="tw:max-w-lg">
<AccordionItem value="delivery">
<AccordionTrigger>What are your delivery options?</AccordionTrigger>
<AccordionContent>
We offer scheduled farm delivery (2-3 days), branch pickup (same day),
and direct ship from suppliers. Free delivery on bulk orders.
</AccordionContent>
</AccordionItem>
<AccordionItem value="returns">
<AccordionTrigger>What is your return policy?</AccordionTrigger>
<AccordionContent>
Returns accepted within 30 days. Products must be unopened and in
original packaging. Credits are applied to your account within 5-7
business days.
</AccordionContent>
</AccordionItem>
<AccordionItem value="support">
<AccordionTrigger>How can I contact customer support?</AccordionTrigger>
<AccordionContent>
Reach your account team via email, live chat, or phone. We respond
within 24 hours during business days.
</AccordionContent>
</AccordionItem>
</Accordion>
);
}

Use the following composition to build an Accordion:

Accordion
├── AccordionItem
│ ├── AccordionTrigger
│ └── AccordionContent
└── AccordionItem
├── AccordionTrigger
└── AccordionContent

A basic accordion that shows one item at a time. The first item is open by default.

Code
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@falcon/ui-kit";
const items = [
{
value: "item-1",
trigger: "How do I reset my password?",
content:
"Click on 'Forgot Password' on the login page, enter your email address, and we'll send you a link to reset your password. The link will expire in 24 hours.",
},
{
value: "item-2",
trigger: "Can I change an order after it is placed?",
content:
"Yes, you can update quantities or products on an open order at any time from your orders page. Changes will be reflected on your next invoice.",
},
{
value: "item-3",
trigger: "What payment methods do you accept?",
content:
"We accept all major credit cards, ACH transfers, and checks. All payments are processed securely through our payment partners.",
},
];
export function Example() {
return (
<Accordion defaultValue={["item-1"]} className="tw:max-w-lg">
{items.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger>{item.trigger}</AccordionTrigger>
<AccordionContent>{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
);
}

Use the multiple prop to allow multiple items to be open at the same time.

Code
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@falcon/ui-kit";
const items = [
{
value: "notifications",
trigger: "Notification Settings",
content:
"Manage how you receive notifications. You can enable email alerts for order updates or push notifications for mobile devices.",
},
{
value: "privacy",
trigger: "Privacy & Security",
content:
"Control your privacy settings and security preferences. Enable two-factor authentication, manage connected devices, review active sessions, and configure data sharing preferences. You can also download your data or delete your account.",
},
{
value: "billing",
trigger: "Billing & Statements",
content:
"View your account balance, payment history, and upcoming invoices. Update your payment method, download monthly statements, or enroll in prepay.",
},
];
export function Example() {
return (
<Accordion
multiple
className="tw:max-w-lg"
defaultValue={["notifications"]}
>
{items.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger>{item.trigger}</AccordionTrigger>
<AccordionContent>{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
);
}

Use the disabled prop on AccordionItem to disable individual items.

Code
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@falcon/ui-kit";
export function Example() {
return (
<Accordion className="tw:w-full">
<AccordionItem value="item-1">
<AccordionTrigger>Can I access my order history?</AccordionTrigger>
<AccordionContent>
Yes, you can view your complete order history including all invoices,
deliveries, and support tickets in the Order History section of your
dashboard.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2" disabled>
<AccordionTrigger>Prepay balance information</AccordionTrigger>
<AccordionContent>
This section contains information about prepay balances. Contact your
retailer to enable prepay on this account.
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3">
<AccordionTrigger>How do I update my email address?</AccordionTrigger>
<AccordionContent>
You can update your email address in your account settings.
You&apos;ll receive a verification email at your new address to
confirm the change.
</AccordionContent>
</AccordionItem>
</Accordion>
);
}

Add tw:border to the Accordion and tw:border-b tw:last:border-b-0 to the AccordionItem to add borders to the items.

Code
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@falcon/ui-kit";
const items = [
{
value: "billing",
trigger: "How does billing work?",
content:
"We offer monthly statements and prepay accounts. Invoices are issued at delivery, and you can pay by check, ACH, or card. All accounts include itemized invoices, season-end summaries, and shared access for farm partners.",
},
{
value: "security",
trigger: "Is my data secure?",
content:
"Yes. We use end-to-end encryption, SOC 2 Type II compliance, and regular third-party security audits. All data is encrypted at rest and in transit using industry-standard protocols.",
},
{
value: "integration",
trigger: "What integrations do you support?",
content:
"We integrate with popular agronomy, accounting, and farm management tools. You can also build custom integrations using our REST API and webhooks.",
},
];
export function Example() {
return (
<Accordion
className="tw:max-w-lg tw:rounded-lg tw:border"
defaultValue={["billing"]}
>
{items.map((item) => (
<AccordionItem
key={item.value}
value={item.value}
className="tw:border-b tw:px-4 tw:last:border-b-0"
>
<AccordionTrigger>{item.trigger}</AccordionTrigger>
<AccordionContent>{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
);
}

Wrap the Accordion in a Card component.

Code
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@falcon/ui-kit";
const items = [
{
value: "financing",
trigger: "What financing options do you offer?",
content:
"We offer standard terms (net 30), seasonal financing, and prepay discounts. Each option includes different rates and due dates based on your account standing.",
},
{
value: "billing",
trigger: "How does billing work?",
content:
"Invoices are issued automatically when orders are delivered. We accept checks, ACH transfers, and all major credit cards. You'll receive an invoice via email after each delivery.",
},
{
value: "cancel",
trigger: "How do I cancel an order?",
content:
"You can cancel an open order anytime from your orders page. There are no cancellation fees before fulfillment. Allocated product is returned to inventory when you cancel.",
},
];
export function Example() {
return (
<Card className="tw:w-full tw:max-w-sm">
<CardHeader>
<CardTitle>Billing & Payments</CardTitle>
<CardDescription>
Common questions about your account, financing, payments and
cancellations.
</CardDescription>
</CardHeader>
<CardContent>
<Accordion defaultValue={["financing"]}>
{items.map((item) => (
<AccordionItem key={item.value} value={item.value}>
<AccordionTrigger>{item.trigger}</AccordionTrigger>
<AccordionContent>{item.content}</AccordionContent>
</AccordionItem>
))}
</Accordion>
</CardContent>
</Card>
);
}

Groups all parts of the accordion. Renders a <div> element and accepts standard <div> props. Use render to replace the element. Items are always stacked vertically, and arrow-key navigation wraps from the last trigger back to the first.

className?: string

CSS class applied to the element.

defaultValue?: AccordionValue<TValue>

The uncontrolled value of the item(s) that should be initially expanded. To render a controlled accordion, use the value prop instead.

disabled?: boolean

Whether the component should ignore user interaction.

hiddenUntilFound?: boolean

Allows the browser’s built-in page search to find and expand the panel contents. Overrides the keepMounted prop and uses hidden="until-found" to hide the element without removing it from the DOM.

keepMounted?: boolean

Whether to keep the element in the DOM while the panel is closed. This prop is ignored when hiddenUntilFound is used.

multiple?: boolean

Whether multiple items can be open at the same time.

onValueChange?: ((value: AccordionValue<TValue>, eventDetails: AccordionRootChangeEventDetails) => void)

Event handler called when an accordion item is expanded or collapsed. Provides the new value as an argument.

render?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, AccordionPrimitive.Root.State<TValue>>

Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a React element or a function that returns the element to render.

style?: React.CSSProperties | ((state: AccordionPrimitive.Root.State<TValue>) => React.CSSProperties | undefined)

Style applied to the element, or a function that returns a style object based on the component’s state.

value?: AccordionValue<TValue>

The controlled value of the item(s) that should be expanded. To render an uncontrolled accordion, use the defaultValue prop instead.

A collapsible panel with the accordion item contents. Renders a <div> element and accepts standard <div> props. Use render to replace the outer panel element. Its className applies to the inner content wrapper. Pair it with AccordionTrigger in an AccordionItem.

className?: string

CSS class applied to the inner content wrapper.

hiddenUntilFound?: boolean

Allows the browser’s built-in page search to find and expand the panel contents. Overrides the keepMounted prop and uses hidden="until-found" to hide the element without removing it from the DOM.

keepMounted?: boolean

Whether to keep the element in the DOM while the panel is closed. This prop is ignored when hiddenUntilFound is used.

render?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, AccordionPanelState>

Allows you to replace the outer panel element with a different tag, or compose it with another component. Accepts a React element or a function that returns the element to render. The className prop still applies to the inner content wrapper.

style?: React.CSSProperties | ((state: AccordionPanelState) => React.CSSProperties | undefined)

Style applied to the element, or a function that returns a style object based on the component’s state.

Groups an accordion header with the corresponding panel. Renders a <div> element and accepts standard <div> props. Use render to replace the element.

className?: string

CSS class applied to the element.

disabled?: boolean

Whether the component should ignore user interaction.

onOpenChange?: ((open: boolean, eventDetails: AccordionPrimitive.Item.ChangeEventDetails) => void)

Event handler called when the panel is opened or closed.

render?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, AccordionItemState>

Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a React element or a function that returns the element to render.

style?: React.CSSProperties | ((state: AccordionItemState) => React.CSSProperties | undefined)

Style applied to the element, or a function that returns a style object based on the component’s state.

value?: any

A unique value that identifies this accordion item. If no value is provided, a unique ID is generated automatically. Use when controlling the accordion programmatically or setting an initial open state.

A button that opens and closes the corresponding panel. Renders a <button> element wrapped in a heading and accepts standard <button> props. Use render to replace the element. Pair it with AccordionContent in an AccordionItem. When using render or nativeButton={false}, provide an accessible interactive control and trigger label. The trigger includes its own decorative expand and collapse icon.

className?: string

CSS class applied to the element.

nativeButton?: boolean = true

Whether the component renders a native <button> element when replacing it via the render prop. Set to false if the rendered element is not a button.

render?: React.ReactElement<any, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, AccordionTriggerState>

Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a React element or a function that returns the element to render.

style?: React.CSSProperties | ((state: AccordionTriggerState) => React.CSSProperties | undefined)

Style applied to the element, or a function that returns a style object based on the component’s state.