Redpanda UI
RC
Redpanda UI

Accordion

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

Made by imskyleen
Loading component...

Installation

Usage

Basic Example

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

<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>

Custom Animation

<Accordion type="single" collapsible>
  <AccordionItem value="animated">
    <AccordionTrigger 
      transition={{ type: 'spring', stiffness: 200, damping: 25 }}
    >
      Custom Animation
    </AccordionTrigger>
    <AccordionContent 
      transition={{ type: 'spring', stiffness: 180, damping: 20 }}
    >
      This accordion uses custom spring animation settings for smoother transitions.
    </AccordionContent>
  </AccordionItem>
</Accordion>

Without Chevron

<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

Loading component...

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

<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, Tailwind CSS, and Motion.
    </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>

Contained with Custom Elements

Loading component...

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

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-muted-foreground" />}
      end={<Badge variant="green">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-muted-foreground" />}
      end={<Badge variant="gray">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-muted-foreground" />}
      end={<Badge variant="green">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:

Accordion Container
┌─────────────────────────────────────────────────┐
│ AccordionItem (value="item-1")                  │
│ ┌─────────────────────────────────────────────┐ │
│ │ AccordionHeader                             │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ AccordionTrigger (clickable)            │ │ │
│ │ │ [Text Content] [ChevronDown Icon] ────┐ │ │ │
│ │ └─────────────────────────────────────────┘ │ │ │
│ └─────────────────────────────────────────────┘ │ │
│ ┌─────────────────────────────────────────────┐ │ │
│ │ AccordionContent (animated)                 │ │ │
│ │ [Expandable content with mask animation]    │ │ │
│ └─────────────────────────────────────────────┘ │ │
├─────────────────────────────────────────────────┤ │
│ 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: Motion components provide smooth height and opacity transitions
  • Accessibility: Built on Radix UI primitives for keyboard navigation and screen readers
  • Chevron Animation: Icon rotates 180° when content expands using Motion

Props

Animate UI Props

Accordion

Prop

Type

AccordionTrigger

Prop

Type

AccordionContent

Prop

Type

Don't delete from the DOM

The choice made is the same as Radix UI, i.e. 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, please replace the AccordionContent component with:

components/redpanda-ui/accordion.tsx
function AccordionContent({
  className,
  children,
  transition = { type: 'spring', stiffness: 150, damping: 22 },
  ...props
}: AccordionContentProps) {
  const { isOpen } = useAccordionItem();

  return (
    <AccordionPrimitive.Content forceMount {...props}>
      <motion.div
        key="accordion-content"
        initial={{ height: 0, opacity: 0, '--mask-stop': '0%' }}
        animate={
          isOpen
            ? { height: 'auto', opacity: 1, '--mask-stop': '100%' }
            : { height: 0, opacity: 0, '--mask-stop': '0%' }
        }
        transition={transition}
        style={{
          maskImage:
            'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',
          WebkitMaskImage:
            'linear-gradient(black var(--mask-stop), transparent var(--mask-stop))',
        }}
        className="overflow-hidden"
        ref={ref}
      >
        <div className={cn('pb-4 pt-0 text-sm', className)}>{children}</div>
      </motion.div>
    </AccordionPrimitive.Content>
  );
}

Credits

Built by malinskibeniamin. The source code is available on GitHub.

On this page