ComponentSite
Accordion
Expandable question and answer rows with a rotating chevron.
$ npx context-ds add accordionUsage
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’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).