AccordionDesign system
ComponentSite

Accordion

Expandable question and answer rows with a rotating chevron.

npx context-ds add accordion
On the site

Usage

Use it for

FAQs.

Avoid

  • Hiding essential content

Dependencies: @radix-ui/react-accordion, lucide-react

Example

examples/accordion.tsx
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";export function Site() {  return (    <Accordion type="single" collapsible defaultValue="a" className="w-full max-w-xl">      <AccordionItem value="a">        <AccordionTrigger>Do you respect robots.txt?</AccordionTrigger>        <AccordionContent>Yes. Every crawl follows the site&rsquo;s rules unless you own the domain.</AccordionContent>      </AccordionItem>      <AccordionItem value="b">        <AccordionTrigger>Is there a free plan?</AccordionTrigger>        <AccordionContent>Yes: 1,000 credits a month, no card required.</AccordionContent>      </AccordionItem>    </Accordion>  );}

Source

components/ui/accordion.tsx
"use client";import * as React from "react";import * as AccordionPrimitive from "@radix-ui/react-accordion";import { ChevronDown } from "lucide-react";import { cn } from "@/lib/utils";// The site's FAQ list (the quick view in src/components/sections/faq.tsx): questions in medium weight on light rules, a// chevron that turns over when open (or your own icon), the answer in muted body-sm opening in a short ease-out.function Accordion(props: React.ComponentProps<typeof AccordionPrimitive.Root>) {  return <AccordionPrimitive.Root data-slot="accordion" {...props} />;}function AccordionItem({ className, ...props }: React.ComponentProps<typeof AccordionPrimitive.Item>) {  return <AccordionPrimitive.Item data-slot="accordion-item" className={cn("border-b border-line", className)} {...props} />;}function AccordionTrigger({ className, children, icon, ...props }: React.ComponentProps<typeof AccordionPrimitive.Trigger> & { icon?: React.ReactNode | null }) {  return (    <AccordionPrimitive.Header className="flex">      <AccordionPrimitive.Trigger        data-slot="accordion-trigger"        className={cn(          "flex flex-1 items-center justify-between gap-4 py-4 text-left font-medium tracking-normal text-fg outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-focus-ring disabled:pointer-events-none disabled:opacity-50 max-md:gap-3 [&[data-state=open]>svg]:rotate-180",          className,        )}        {...props}      >        {children}        {icon === undefined ? <ChevronDown className="size-4 shrink-0 transition-transform duration-200 ease-out motion-reduce:transition-none" /> : icon}      </AccordionPrimitive.Trigger>    </AccordionPrimitive.Header>  );}function AccordionContent({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Content>) {  return (    <AccordionPrimitive.Content      data-slot="accordion-content"      className="overflow-hidden text-body-sm leading-5 text-fg-muted data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down motion-reduce:animate-none"      {...props}    >      <div className={cn("pb-4", className)}>{children}</div>    </AccordionPrimitive.Content>  );}export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };

Reference: src/components/ui/accordion.tsx; src/components/sections/faq.tsx (quick view).