Light

Accordion

A vertically stacked set of interactive headings that each reveal a section of content. Built on [Radix Accordion](https://www.radix-ui.com/primitives/docs/components/accordion).

Spec · from metadata

When to use

  • FAQ sections with question/answer pairs
  • Collapsible settings or filter groups
  • Progressive disclosure of dense content

When not to use

  • For switching between views — use Tabs instead
  • For a single collapsible section — use Collapsible instead
  • For navigation menus — use NavigationMenu or Sidebar instead

Anti-patterns

Avoid<Accordion><AccordionTrigger>Title</AccordionTrigger><AccordionContent>Body</AccordionContent></Accordion>
Prefer<Accordion type="single" collapsible><AccordionItem value="item-1"><AccordionTrigger>Title</AccordionTrigger><AccordionContent>Body</AccordionContent></AccordionItem></Accordion>

AccordionTrigger and AccordionContent must be wrapped in AccordionItem with a value prop

Avoid<Accordion type="single"><AccordionItem value="a">...</AccordionItem></Accordion>
Prefer<Accordion type="single" collapsible><AccordionItem value="a">...</AccordionItem></Accordion>

Without `collapsible`, one item must always remain open — usually not the desired UX

Accessibility

  • Required ARIAaria-expanded (managed by Radix)aria-controls (managed by Radix)
  • Screen readerRadix handles aria-expanded and heading semantics automatically via AccordionPrimitive.Header

Token bindings

TokenCategoryUsage
border-bcolorSeparator between accordion items
text-muted-foregroundcolorChevron icon color
duration-200motionChevron rotation and content expand/collapse animation duration

Import

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@timelycare/helix-ui"

Props

Accordion (Root)

interface AccordionProps {
  type?: "single" | "multiple"  // Allow one or multiple items open
  collapsible?: boolean         // Allow closing all items (single mode only)
  defaultValue?: string | string[]
  value?: string | string[]
  onValueChange?: (value: string | string[]) => void
  className?: string
  children: React.ReactNode
}

AccordionItem

interface AccordionItemProps {
  value: string               // Unique identifier for the item
  disabled?: boolean          // Prevents opening/closing this item
  className?: string
  children: React.ReactNode
}

AccordionTrigger

interface AccordionTriggerProps {
  children: React.ReactNode
  className?: string
}

AccordionContent

interface AccordionContentProps {
  children: React.ReactNode
  className?: string
}

Variations

The accordion supports five distinct variations. Each can be combined as needed.

VariationWhen to UseKey Prop / Pattern
BasicFAQs, settings — only one section visible at a timetype="single" collapsible
MultipleComparing sections side-by-side, settings panelstype="multiple"
DisabledGating premium content, temporarily unavailable sectionsdisabled on AccordionItem
BordersVisually contained accordion within a page sectionborder + rounded-lg on root, border-b px-4 last:border-b-0 on items
CardGrouped FAQ or settings block with a heading and descriptionWrap Accordion inside a Card component

Basic (Single Collapsible)

The default variation. Only one item can be open at a time. Adding collapsible allows the user to close the currently open item. Use defaultValue to pre-expand an item on load.

<Accordion type="single" collapsible defaultValue="item-1" className="max-w-lg">
  <AccordionItem value="item-1">
    <AccordionTrigger>How do I reset my password?</AccordionTrigger>
    <AccordionContent>
      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.
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-2">
    <AccordionTrigger>Can I change my subscription plan?</AccordionTrigger>
    <AccordionContent>
      Yes, you can upgrade or downgrade your plan at any time from your
      account settings. Changes will be reflected in your next billing cycle.
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-3">
    <AccordionTrigger>What payment methods do you accept?</AccordionTrigger>
    <AccordionContent>
      We accept all major credit cards, PayPal, and bank transfers. All
      payments are processed securely through our payment partners.
    </AccordionContent>
  </AccordionItem>
</Accordion>

Design guidance:

  • Best for FAQ pages where showing one answer at a time keeps the page scannable.
  • Always include collapsible so users can close all items — without it the user is forced to keep one item open.
  • Use defaultValue to open the most relevant item on load (e.g. the first one).

Multiple

Use type="multiple" to allow more than one item to be expanded simultaneously. The defaultValue prop accepts an array of item values.

<Accordion type="multiple" className="max-w-lg" defaultValue={["notifications"]}>
  <AccordionItem value="notifications">
    <AccordionTrigger>Notification Settings</AccordionTrigger>
    <AccordionContent>
      Manage how you receive notifications. You can enable email alerts
      for updates or push notifications for mobile devices.
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="privacy">
    <AccordionTrigger>Privacy & Security</AccordionTrigger>
    <AccordionContent>
      Control your privacy settings and security preferences. Enable
      two-factor authentication, manage connected devices, and review
      active sessions.
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="billing">
    <AccordionTrigger>Billing & Subscription</AccordionTrigger>
    <AccordionContent>
      View your current plan, payment history, and upcoming invoices.
      Update your payment method or change your subscription tier.
    </AccordionContent>
  </AccordionItem>
</Accordion>

Design guidance:

  • Use when users need to compare or reference multiple sections at once (e.g. account settings panels).
  • The collapsible prop is not needed — each item toggles independently.
  • Consider whether content length makes this overwhelming; if sections are very long, single mode may be better.

Disabled

Add disabled to individual AccordionItem components to prevent them from being toggled. Disabled items render with reduced opacity and a not-allowed cursor.

<Accordion type="single" collapsible className="w-full">
  <AccordionItem value="item-1">
    <AccordionTrigger>Can I access my account history?</AccordionTrigger>
    <AccordionContent>
      Yes, you can view your complete account history including all
      transactions, plan changes, and support tickets.
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="item-2" disabled>
    <AccordionTrigger>Premium feature information</AccordionTrigger>
    <AccordionContent>
      This section contains information about premium features.
      Upgrade your plan to access this content.
    </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.
    </AccordionContent>
  </AccordionItem>
</Accordion>

Design guidance:

  • Use to indicate locked or gated content (e.g. premium-only FAQ sections).
  • Disabled items are visually muted (opacity-50) and non-interactive.
  • Combine with a lock icon or "Upgrade" badge in the trigger text to communicate why the item is disabled.

Borders

Add border and rounded-lg to the Accordion root and border-b px-4 last:border-b-0 to each AccordionItem to create a contained, bordered look.

<Accordion
  type="single"
  collapsible
  className="max-w-lg rounded-lg border"
  defaultValue="billing"
>
  <AccordionItem value="billing" className="border-b px-4 last:border-b-0">
    <AccordionTrigger>How does billing work?</AccordionTrigger>
    <AccordionContent>
      We offer monthly and annual subscription plans. Billing is charged at
      the beginning of each cycle, and you can cancel anytime.
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="security" className="border-b px-4 last:border-b-0">
    <AccordionTrigger>Is my data secure?</AccordionTrigger>
    <AccordionContent>
      Yes. We use end-to-end encryption, SOC 2 Type II compliance, and
      regular third-party security audits.
    </AccordionContent>
  </AccordionItem>
  <AccordionItem value="integration" className="border-b px-4 last:border-b-0">
    <AccordionTrigger>What integrations do you support?</AccordionTrigger>
    <AccordionContent>
      We integrate with 500+ popular tools including Slack, Zapier,
      Salesforce, HubSpot, and more.
    </AccordionContent>
  </AccordionItem>
</Accordion>

Design guidance:

  • Creates a visually distinct, self-contained block — good for embedding an accordion within a larger page layout.
  • The rounded border gives it a "panel" appearance without using a Card.
  • Items get horizontal padding (px-4) since the container border provides the visual boundary.

Card

Wrap the Accordion inside a Card component to group items under a shared heading and description. This is the most structured variation.

<Card className="w-full max-w-sm">
  <CardHeader>
    <CardTitle>Subscription & Billing</CardTitle>
    <CardDescription>
      Common questions about your account, plans, payments and cancellations.
    </CardDescription>
  </CardHeader>
  <CardContent>
    <Accordion type="single" collapsible defaultValue="plans">
      <AccordionItem value="plans">
        <AccordionTrigger>What subscription plans do you offer?</AccordionTrigger>
        <AccordionContent>
          We offer three tiers: Starter ($9/month), Professional ($29/month),
          and Enterprise ($99/month).
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="billing">
        <AccordionTrigger>How does billing work?</AccordionTrigger>
        <AccordionContent>
          Billing occurs automatically at the start of each cycle. We accept
          all major credit cards, PayPal, and ACH transfers.
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="cancel">
        <AccordionTrigger>How do I cancel my subscription?</AccordionTrigger>
        <AccordionContent>
          Cancel anytime from your account settings. No cancellation fees.
          Access continues until the end of your current billing period.
        </AccordionContent>
      </AccordionItem>
    </Accordion>
  </CardContent>
</Card>

Design guidance:

  • Best for sidebar panels, modal content, or self-contained FAQ blocks.
  • The CardHeader provides context so users understand what the accordion covers before interacting.
  • Keep item count to 3–5 to avoid an overly tall card.

States

StateTrigger TextIconImplementation
Defaulttext-foregroundtext-muted-foregroundBase appearance
HoverunderlineUnchangedhover:underline on trigger text
FocusRing outlineUnchangedfocus-visible:ring-[3px] focus-visible:ring-ring
Opentext-foregroundRotated 180°[data-state=open]>svg:rotate-180
Disabledopacity-50opacity-50disabled:opacity-50 disabled:pointer-events-none

Styling

Typography

ElementFontSizeWeightLine HeightColor
Triggerfont-sans (Adelle Sans)text-sm (14px)font-medium (500)leading-5 (20px)text-foreground
Contentfont-sans (Adelle Sans)text-sm (14px)font-normal (400)leading-5 (20px)text-muted-foreground

Spacing

ElementPropertyValue
AccordionTriggerPaddingpy-4 (16px vertical)
AccordionContentPaddingpb-4 (16px bottom)
Borders variation itemsHorizontal paddingpx-4 (16px)

Borders

PropertyValue
Item separatorborder-b border-border (bottom)
Borders variation containerborder rounded-lg
Card variationUses Card component border and shadow

Icons

Icon: ChevronDown from lucide-react Size: size-4 (16×16px) Color: text-muted-foreground Animation: transition-transform duration-200 with rotate-180 when [data-state=open] Alignment: shrink-0, positioned at end of trigger row via justify-between

<ChevronDown className="size-4 shrink-0 text-muted-foreground transition-transform duration-200" />

Component Structure

<div className="border-b border-border">
  {/* AccordionTrigger */}
  <button className="flex w-full items-center justify-between py-4 text-sm font-medium hover:underline [&[data-state=open]>svg]:rotate-180">
    {children}
    <ChevronDown className="size-4 shrink-0 text-muted-foreground transition-transform duration-200" />
  </button>

  {/* AccordionContent (when expanded) */}
  <div className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down">
    <div className="pb-4 text-muted-foreground">
      {children}
    </div>
  </div>
</div>

Accessibility

  • Built on Radix Accordion — keyboard navigation and focus management handled automatically
  • Keyboard: Enter/Space to toggle, Arrow Up/Down to move between triggers
  • ARIA: aria-expanded on triggers, aria-controls linking trigger to content panel
  • Focus: Visible focus ring via focus-visible:ring-ring
  • Disabled items are excluded from keyboard navigation

Choosing the Right Variation

ScenarioRecommended Variation
FAQ page or help centerBasic (single collapsible)
Settings page with multiple sectionsMultiple
Content with premium/locked sectionsDisabled items within Basic or Multiple
Accordion as a standalone block on a pageBorders
Sidebar panel or grouped content with headingCard
Comparing information across sectionsMultiple

Gotchas

ProblemSolution
Item won't close in single modeAdd collapsible prop to <Accordion>
Multiple items open when shouldn'tUse type="single" not type="multiple"
Chevron not animatingEnsure transition-transform and [data-state=open]>svg:rotate-180 classes are present
Disabled item still clickableUse disabled prop on AccordionItem, not on the trigger button directly
Borders variation items not paddedAdd px-4 to AccordionItem className, not to the root
Card variation too wideSet max-w-sm or max-w-md on the Card wrapper

See Also


Figma Reference

View in Figma


Last updated: February 20, 2026