DEV Community

Cover image for 5+ Best Accordion Components for Modern Web UIs (with Code)
Vaibhav Gupta
Vaibhav Gupta

Posted on

5+ Best Accordion Components for Modern Web UIs (with Code)

Accordions are one of the most underrated UI patterns — they declutter interfaces, improve content scanning, and make complex pages feel simpler without losing information. In this guide, we’ll explore the best accordion components available today, how they work, and how to use them with React, Tailwind CSS, and shadcn/ui.


Why Accordions Matter

Before we dive into examples:

  • They organize long content into digestible sections.
  • They’re perfect for FAQs, dashboards, documentation, or settings panels.
  • Good accordion components are accessible, keyboard-friendly, and highly customizable.

Anatomy of an Accordion

Every modern accordion has:

  • A wrapper
  • One or more items
  • A trigger (the clickable header)
  • The content section that expands/collapses on interaction

In React + shadcn/ui, these map to:

<Accordion>, <AccordionItem>, <AccordionTrigger>, and <AccordionContent>.


1. shadcn/ui Accordion (React + Tailwind CSS)

This is one of the cleanest React Accordion implementations out there — unstyled by default, accessible, and composable.

Install (CLI Command)

npx shadcn@latest add @shadcn-space/accordion-01
Enter fullscreen mode Exit fullscreen mode

Basic Usage

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion";
import { cn } from "@/lib/utils";
import { FileText, Folder, LucideIcon, Settings, Users } from "lucide-react";

const data: {
  value: string;
  title: string;
  subtitle: string;
  content: string;
  icon: LucideIcon;
  textColor: string;
  bgColor: string;
}[] = [
  {
    value: "documents",
    title: "Documents",
    subtitle: "Manage your files",
    content:
      "View, upload, and organize all your documents in one place. Keep everything structured and easy to find.",
    icon: FileText,
    textColor: "text-blue-500",
    bgColor: "bg-blue-500/10",
  },
  {
    value: "projects",
    title: "Projects",
    subtitle: "Organize your work",
    content:
      "Group related files and tasks into projects to keep your workflow clean and efficient.",
    icon: Folder,
    textColor: "text-orange-400",
    bgColor: "bg-orange-400/10",
  },
  {
    value: "settings",
    title: "Settings",
    subtitle: "Customize your experience",
    content:
      "Adjust preferences, update account details, and configure application behavior.",
    icon: Settings,
    textColor: "text-teal-400",
    bgColor: "bg-teal-400/10",
  },
  {
    value: "team",
    title: "Team Members",
    subtitle: "Manage users and roles",
    content:
      "Invite new members, assign roles, and control access permissions for your team.",
    icon: Users,
    textColor: "text-red-500",
    bgColor: "bg-red-500/10",
  },
];

const AccordionDemo = () => (
  <div className="flex items-center justify-center max-w-md w-full">
    <Accordion
      className="w-full -space-y-px"
      defaultValue={[data[0].value]}
    >
      {data.map((item) => {
        const Icon = item.icon;
        return (
          <AccordionItem
            key={item.value}
            value={item.value}
            className="border bg-background px-4 first:rounded-t-lg last:rounded-b-lg last:border-b"
          >
            <AccordionTrigger className="hover:no-underline">
              <div className="flex items-center gap-3">
                <div
                  className={cn(
                    "p-2.5 rounded-xl",
                    item.bgColor,
                    item.textColor
                  )}
                >
                  <Icon size={20} className="size-5" />
                </div>
                <div className="flex flex-col items-start text-left">
                  <span>{item.title}</span>
                  <span className="text-sm text-muted-foreground">
                    {item.subtitle}
                  </span>
                </div>
              </div>
            </AccordionTrigger>
            <AccordionContent className="ps-14">
              <p className="text-muted-foreground">{item.content}</p>
            </AccordionContent>
          </AccordionItem>
        );
      })}
    </Accordion>
  </div>
);

export default AccordionDemo;
Enter fullscreen mode Exit fullscreen mode

Notes

  • type="single" lets only one section open at a time.

  • Use type="multiple" for many open sections.

Checkout this component


2. Multi-Level shadcn Accordion (Nested UI Sections)

Nested accordions are great for deep content like multi-topic FAQs or settings menus.

Install (CLI Command)

Install (CLI Command)

npx shadcn@latest add @shadcn-space/accordion-02

Enter fullscreen mode Exit fullscreen mode

Basic Usage

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion";
import {
  Collapsible,
  CollapsibleContent,
  CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { cn } from "@/lib/utils";
import { ChevronDown, FileText, Folder, Handshake, MinusIcon, PlusIcon, Users } from "lucide-react";

// Static data instead of faker
const items = [
  {
    id: "item-1",
    title: "Company Overview",
    icon: FileText,
    textColor: "text-blue-500",
    bgColor: "bg-blue-500/10",
    collapsibles: [
      {
        id: "collapsible-1-1",
        title: "Mission Statement",
        content:
          "Our mission is to deliver high-quality products that improve the lives of our customers.",
      },
      {
        id: "collapsible-1-2",
        title: "Core Values",
        content:
          "Integrity, innovation, and customer satisfaction are at the heart of everything we do.",
      },
    ],
  },
  {
    id: "item-2",
    title: "Products & Services",
    icon: Folder,
    textColor: "text-orange-400",
    bgColor: "bg-orange-400/10",
    collapsibles: [
      {
        id: "collapsible-2-1",
        title: "Software Solutions",
        content:
          "We offer a range of software tools designed to enhance business efficiency and productivity.",
      },
      {
        id: "collapsible-2-2",
        title: "Consulting Services",
        content:
          "Our consulting team helps clients identify opportunities, streamline operations, and drive growth.",
      },
    ],
  },
  {
    id: "item-3",
    title: "Team & Culture",
    icon: Handshake,
    textColor: "text-teal-400",
    bgColor: "bg-teal-400/10",
    collapsibles: [
      {
        id: "collapsible-3-1",
        title: "Leadership Team",
        content:
          "Our leadership team is composed of experienced professionals committed to innovation and growth.",
      },
      {
        id: "collapsible-3-2",
        title: "Work Environment",
        content:
          "We foster a collaborative and inclusive culture where everyone can thrive.",
      },
    ],
  },
  {
    id: "item-4",
    title: "Contact Information",
    icon: Users,
    textColor: "text-red-500",
    bgColor: "bg-red-500/10",
    collapsibles: [
      {
        id: "collapsible-4-1",
        title: "Support",
        content:
          "Reach out to our support team via email or phone for any inquiries or assistance.",
      },
      {
        id: "collapsible-4-2",
        title: "Locations",
        content:
          "Our offices are located in New York, San Francisco, and London to serve clients globally.",
      },
    ],
  },
];

const AccordionMultiLevelDemo = () => (
  <div className="flex items-center justify-center max-w-md w-full">
    <Accordion
      className="w-full -space-y-1"
      defaultValue={[items[0].id]}
    >
      {items.map((item) => (
        <AccordionItem
          className="overflow-hidden border bg-background first:rounded-t-lg last:rounded-b-lg last:border-b"
          key={item.id}
          value={item.id}
        >
          <AccordionTrigger className="group px-4 py-3 hover:no-underline last:[&>svg]:hidden">
            <div className="flex w-full items-center justify-between gap-3">
              <div className="flex items-center gap-3">
                <div
                  className={cn(
                    "p-2.5 rounded-xl",
                    item.bgColor,
                    item.textColor
                  )}
                >
                  <item.icon size={20} className="size-5" />
                </div>
                <span className="flex-1 text-left">{item.title}</span>
              </div>
              <div className="relative size-4 shrink-0">
                <PlusIcon className="absolute inset-0 size-4 text-muted-foreground transition-opacity duration-200 group-data-[panel-open]:opacity-0" />
                <MinusIcon className="absolute inset-0 size-4 text-muted-foreground opacity-0 transition-opacity duration-200 group-data-[panel-open]:opacity-100" />
              </div>
            </div>
          </AccordionTrigger>
          <AccordionContent className="p-0">
            {item.collapsibles.map((collapsible) => (
              <Collapsible
                className="space-y-1 border-t border-border bg-accent px-4 py-3"
                key={collapsible.id}
              >
                <CollapsibleTrigger className="flex items-center gap-2 font-medium [&[data-state=open]>svg]:rotate-180">
                  <ChevronDown
                    aria-hidden="true"
                    className="shrink-0 opacity-60 transition-transform duration-200"
                    size={16}
                    strokeWidth={2}
                  />
                  {collapsible.title}
                </CollapsibleTrigger>
                <CollapsibleContent className="overflow-hidden ps-6 text-sm text-muted-foreground transition-all data-[state=closed]:animate-collapsible-up data-[state=open]:animate-collapsible-down">
                  {collapsible.content}
                </CollapsibleContent>
              </Collapsible>
            ))}
          </AccordionContent>
        </AccordionItem>
      ))}
    </Accordion>
  </div>
);

export default AccordionMultiLevelDemo;

Enter fullscreen mode Exit fullscreen mode

✨ Useful for hierarchical menus or grouped content.

Checkout this component


3. Tailwind Accordions Without JS (Pure HTML)

If you don’t need React, you can use a pure HTML/CSS accordion based on <details> and <summary>:

import React from 'react'
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from '@/components/ui/accordion'

const BasicAccordiancode = () => {
  return (
    <>
      <Accordion type='single' collapsible className='w-full'>
        <AccordionItem value='item-1'>
          <AccordionTrigger className='text-base font-semibold'>
            Is it accessible?
          </AccordionTrigger>
          <AccordionContent>
            Yes. It adheres to the WAI-ARIA design pattern.
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value='item-2'>
          <AccordionTrigger className='text-base font-semibold'>
            Is it styled?
          </AccordionTrigger>
          <AccordionContent>
            Yes. It comes with default styles that matches the other
            components&apos; aesthetic.
          </AccordionContent>
        </AccordionItem>
        <AccordionItem value='item-3'>
          <AccordionTrigger className='text-base font-semibold'>
            Is it animated?
          </AccordionTrigger>
          <AccordionContent>
            Yes. It&apos;s animated by default, but you can disable it if you
            prefer.
          </AccordionContent>
        </AccordionItem>
      </Accordion>
    </>
  )
}

export default BasicAccordiancode

Enter fullscreen mode Exit fullscreen mode

This works with no JS at all, is SEO-friendly, and accessible.

Checkout this component


4. SmoothUI Animated Accordion (with Framer Motion)

If you want smooth animation built in, SmoothUI’s accordion is worth trying. It uses Framer Motion + Tailwind.

Example

Install via shadcn CLI:

npx shadcn add @smoothui/basic-accordion

Enter fullscreen mode Exit fullscreen mode

Then import and use:

import BasicAccordion from "@/components/smoothui/ui/BasicAccordion"; 
export default function AnimatedFAQ() { 
  return <BasicAccordion />;
}

Enter fullscreen mode Exit fullscreen mode

Why it’s great

  • Smooth expand/collapse transitions

  • Fully customizable via Tailwind classes

  • Works well with dynamic content


5. Headless UI Accordion Variants

Some component registries offer headless accordion solutions that you can style how you like.

E.g., Animate UI Headless Accordion — gives a pure, unstyled experience ready for your animations and classes.

npx shadcn@latest add headless-accordion-demo

Enter fullscreen mode Exit fullscreen mode

This is ideal when you want total control over UI/UX without presets.


Tips for Production-Ready Accordions

Clear headings: Users scan first, click second.

Mobile-optimized: Accordions help on narrow screens.

Keyboard navigation: Always test focus + enter/space interactions.

Controlled vs uncontrolled: Choose based on if the parent needs to manage open state.


When to Use Each Type

Use Case Best Component
Simple FAQ shadcn/ui basic accordion
Nested content Multi-Level Accordion
Rich animations SmoothUI
Framework-agnostic Pure HTML <details>
Headless custom UI Headless Accordion

Wrap-Up

Accordions are more than collapsible boxes — they’re UX boosters. The modern ecosystem around shadcn/ui + Tailwind CSS + React gives you everything from minimalist to animated, deeply customizable accordion components. Pick the one that fits your project’s complexity and UI style, and you’ll make dense content feel effortlessly navigable.

Top comments (0)