Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
Made by imskyleen
Edit on GitHub

Accordion

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

Installation

bash
npx shadcn@latest add @redpanda/accordion
bash
pnpm dlx shadcn@latest add @redpanda/accordion
bash
yarn dlx shadcn@latest add @redpanda/accordion
bash
bunx shadcn@latest add @redpanda/accordion
bash
nubx shadcn@latest add @redpanda/accordion
bash
aube dlx shadcn@latest add @redpanda/accordion

Usage

Basic Example

tsx
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '@/components/redpanda-ui/accordion';
<Accordion type="single" collapsible>  <AccordionItem value="item-1">    <AccordionTrigger>What is Redpanda?</AccordionTrigger>    <AccordionContent>      Redpanda is a streaming data platform that is Kafka-compatible but simpler to operate and 10x faster.    </AccordionContent>  </AccordionItem>  <AccordionItem value="item-2">    <AccordionTrigger>How does it work?</AccordionTrigger>    <AccordionContent>      Redpanda is built from the ground up in C++ and designed to be simple, powerful, and cost-efficient.    </AccordionContent>  </AccordionItem>  <AccordionItem value="item-3">    <AccordionTrigger>Is it production ready?</AccordionTrigger>    <AccordionContent>Yes, Redpanda is production-ready and used by hundreds of companies worldwide.</AccordionContent>  </AccordionItem></Accordion>;

Multiple Items Open

tsx
<Accordion type="multiple">  <AccordionItem value="features">    <AccordionTrigger>Features</AccordionTrigger>    <AccordionContent>      <ul className="list-disc pl-6 space-y-1">        <li>Kafka API compatible</li>        <li>10x faster performance</li>        <li>Built-in schema registry</li>        <li>Tiered storage support</li>      </ul>    </AccordionContent>  </AccordionItem>  <AccordionItem value="pricing">    <AccordionTrigger>Pricing</AccordionTrigger>    <AccordionContent>      Redpanda offers both open source and cloud options with flexible pricing models.    </AccordionContent>  </AccordionItem></Accordion>

Without Chevron

tsx
<Accordion type="single" collapsible>  <AccordionItem value="no-chevron">    <AccordionTrigger chevron={false}>No Chevron Icon</AccordionTrigger>    <AccordionContent>This accordion item doesn't display the chevron indicator.</AccordionContent>  </AccordionItem></Accordion>

Contained Variant

The contained variant provides a more visually distinct card-like appearance with rounded borders and background colors:

tsx
<Accordion type="single" defaultValue="item-1" collapsible variant="contained" className="max-w-[500px] w-full">  <AccordionItem value="item-1">    <AccordionTrigger>What is Redpanda UI?</AccordionTrigger>    <AccordionContent>      Redpanda UI is an open-source distribution of React components built with TypeScript and Tailwind CSS.    </AccordionContent>  </AccordionItem>
  <AccordionItem value="item-2">    <AccordionTrigger>How is it different from other libraries?</AccordionTrigger>    <AccordionContent>      Instead of installing via NPM, you copy and paste the components directly. This gives you full control to modify      or customize them as needed.    </AccordionContent>  </AccordionItem>
  <AccordionItem value="item-3">    <AccordionTrigger>Is Redpanda UI free to use?</AccordionTrigger>    <AccordionContent>      Absolutely! Redpanda UI is fully open-source. You can use, modify, and adapt it to fit your needs.    </AccordionContent>  </AccordionItem></Accordion>

Controlled with Expand / Collapse All

Disabled Item

Contained with Custom Elements

The contained variant supports custom start and end elements for more complex layouts:

tsx
import { Circle, FileText, Settings } from 'lucide-react';import { Badge } from '@/components/badge';
<Accordion type="single" defaultValue="item-1" collapsible variant="contained" className="max-w-[500px] w-full">  <AccordionItem value="item-1">    <AccordionTrigger start={<Circle className="size-4 text-subtle" />} end={<Badge tone="success">Available</Badge>}>      Accordion heading    </AccordionTrigger>    <AccordionContent>      This is the accordion content that provides additional details when the accordion is expanded.    </AccordionContent>  </AccordionItem>
  <AccordionItem value="item-2">    <AccordionTrigger      start={<FileText className="size-4 text-subtle" />}      end={        <Badge tone="default" variant="subtle">          In preview        </Badge>      }    >      Accordion heading    </AccordionTrigger>    <AccordionContent>      This is the accordion content that provides additional details when the accordion is expanded.    </AccordionContent>  </AccordionItem>
  <AccordionItem value="item-3">    <AccordionTrigger start={<Settings className="size-4 text-subtle" />} end={<Badge tone="success">Available</Badge>}>      Accordion heading    </AccordionTrigger>    <AccordionContent>      This is the accordion content that provides additional details when the accordion is expanded.    </AccordionContent>  </AccordionItem></Accordion>;

When to use

Use an accordion when you need to display a large amount of content in a compact, organized way. This component is ideal for:

Use Accordion when:

  • You have FAQ sections or help documentation
  • Content can be grouped into clear, discrete sections
  • Screen space is limited and you need to show/hide content
  • Users typically need to focus on one section at a time
  • You want to provide an overview with expandable details

Don’t use Accordion when:

  • Users need to compare content across sections simultaneously
  • The content sections are very short (use a simple list instead)
  • Navigation between sections is the primary goal (use Tabs instead)
  • The content doesn’t have a natural hierarchical structure

Anatomy

The Accordion component consists of several parts working together:

plaintext
Accordion Container┌─────────────────────────────────────────────────┐│ AccordionItem (value="item-1")                  ││ ┌─────────────────────────────────────────────┐ ││ │ AccordionHeader                             │ ││ │ ┌─────────────────────────────────────────┐ │ ││ │ │ AccordionTrigger (clickable)            │ │ ││ │ │ [Text Content] [ChevronDown Icon] ────┐ │ │ ││ │ └─────────────────────────────────────────┘ │ │ ││ └─────────────────────────────────────────────┘ │ ││ ┌─────────────────────────────────────────────┐ │ ││ │ AccordionContent (animated)                 │ │ ││ │ [Expandable content with CSS height transition] │ │ ││ └─────────────────────────────────────────────┘ │ │├─────────────────────────────────────────────────┤ ││ AccordionItem (value="item-2")                  │ ││ [Similar structure repeats...]                  │ │└─────────────────────────────────────────────────┘ │                                                    │Context Flow:                                       │AccordionItemContext ──────────────────────────────┘├── isOpen: boolean└── setIsOpen: (open: boolean) => void

Component Hierarchy:

  1. Accordion (Root): Manages overall state and behavior (single vs multiple)
  2. AccordionItem: Individual accordion section with unique value
  3. AccordionHeader: Contains the clickable trigger (automatically included)
  4. AccordionTrigger: Clickable element that toggles the content visibility
  5. AccordionContent: Expandable content area with smooth animations

Key Interactions:

  • State Management: Each AccordionItem tracks its open/closed state via context
  • Animation: Base UI CSS transitions provide smooth height changes as the panel expands and collapses
  • Accessibility: Built on Base UI primitives for keyboard navigation and screen readers
  • Chevron Animation: Icon rotates 180° when content expands via a CSS transform transition

Props

Keyboard interactions

Key Action
Tab to trigger Focus moves to the next accordion trigger.
Enter / Space Toggles the focused item.
ArrowDown Moves focus to the next trigger. Wraps at the end.
ArrowUp Moves focus to the previous trigger. Wraps at the start.
Home / End Jumps to first / last trigger.

Accessibility

  • Each AccordionTrigger renders inside an AccordionHeader (an <h3> by default). Override the tag via render on AccordionHeader if the heading level doesn’t match your document outline.
  • Triggers expose aria-expanded, aria-controls, and Base UI’s native data-panel-open attribute — CSS selectors like data-[panel-open]:rotate-180 keep working.
  • In type="single" mode the currently-open item can always be collapsed again.

Component Props

Accordion

PropType
variant?'simple' | 'contained'

The visual style variant of the accordion

Type'simple' | 'contained'
Default'simple'

AccordionTrigger

PropType
chevron?boolean

Whether to show the accordion chevron

Typeboolean
Defaulttrue
start?React.ReactNode

Optional element to display at the start of the trigger (e.g., icons)

TypeReact.ReactNode
Defaultundefined
end?React.ReactNode

Optional element to display at the end of the trigger before the chevron (e.g., badges)

TypeReact.ReactNode
Defaultundefined

Don’t delete from the DOM

The choice made (also Base UI’s default) is to remove the element from the DOM for accessibility and performance reasons. However, this may pose a problem for SEO. If you want your Accordion content to be taken into account by Google, replace the AccordionContent component with:

components/redpanda-ui/accordion.tsx
function AccordionContent({ className, children, ...props }: AccordionContentProps) {  const { variant } = useAccordionItem();
  return (    <AccordionPrimitive.Panel      className="h-(--accordion-panel-height) overflow-hidden transition-[height] duration-200 ease-out data-[ending-style]:h-0 data-[starting-style]:h-0"      data-slot="accordion-content"      keepMounted      {...props}    >      <div className={cn(accordionContentVariants({ variant }), className)}>{children}</div>    </AccordionPrimitive.Panel>  );}

Credits

  • We use Base UI for the accordion component.
  • We take our inspiration from Shadcn UI for the accordion style.

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
  • patchv0.3.1## 🚧 Updated#112
See full history →

Last updated on

Was this page helpful?