Skip to content
Drivn logoDrivn
5 min read

How to Add an Accordion to a React App

Step-by-step guide to adding a copy-and-own Accordion to any React project using the Drivn CLI — zero runtime UI deps, dot notation, and Tailwind.

Adding an accordion to a React app sounds trivial until you actually start. You can build one from scratch in an afternoon — managing open state, animating height, handling the chevron rotation — and learn first-hand why seasoned teams usually reach for a library. Or you can pull in a headless primitive like Radix and spend a day wiring its context providers, keyboard handlers, and data-state styling until the component matches your design system.

Drivn sits in a third place. It is not a runtime package; the CLI writes a component source file directly into your repo, and that source carries no third-party UI dependencies. You get a working Accordion you can read end-to-end, ship, and modify without forking a package. This guide walks through adding it to an existing React app in about ten minutes — install the CLI, copy the component, drop it on a page, and adjust the style tokens to match your theme.

You can complete this guide with a vanilla React + Vite project, a Next.js App Router app, a Remix site, or any React framework that supports Tailwind and TypeScript. The steps are the same. For broader setup context see the installation page; for the framework-specific variant see the Next.js Accordion guide; for live examples see the Accordion examples page.

Prerequisites

Before installing the Accordion, make sure your React project has the three things Drivn assumes: Tailwind CSS v4 installed and processing your CSS, TypeScript configured (the component ships as a .tsx file), and a @/ path alias pointing at your source directory. If you used create-next-app, npm create vite, or npx drivn@latest create, all three are wired up automatically. For a custom setup, open your tsconfig.json and verify the compilerOptions.paths entry; the installation page lists the minimal viable config. Drivn also expects lucide-react as its only runtime dependency — the CLI adds it automatically during install if it is missing from your package.json. No PostCSS plugins, Babel presets, or Tailwind config changes are required.

Step 1 — Install Drivn via the CLI

Run the CLI from your project root to add the accordion source file. The command prompts once for your install directory (defaulting to src/components/ui/), then writes accordion.tsx and adds lucide-react to your package.json if it is not already present. No global config file is created — the Accordion is just a TypeScript file in your repo that you can edit like any other component. Confirm the file landed correctly with ls or in your editor, then commit the change. If your project uses a monorepo layout or a non-standard path, the CLI docs cover the --cwd and --dir flags used to target a custom location during install.

1# add the Accordion to your existing React project
2npx drivn add accordion
3
4# verify the file was written
5ls src/components/ui/accordion.tsx

Step 2 — Import and render the Accordion

Open the page where the Accordion should live and import the compound component from your UI directory. The API uses dot notation — one import exposes Accordion, Accordion.Item, Accordion.Trigger, and Accordion.Content — so every accordion on every page uses a single import line. Each Accordion.Item needs a unique value string; the root tracks which items are open in a local Set keyed by those values. Render the same accordion on a landing page, inside a dialog, or as a filter panel — the component does not care about its container. See the Accordion docs for the full prop table and every variant, and the examples page for five complete patterns you can copy.

1import { Accordion } from '@/components/ui/accordion'
2
3export function Faq() {
4 return (
5 <Accordion>
6 <Accordion.Item value="what">
7 <Accordion.Trigger>What is Drivn?</Accordion.Trigger>
8 <Accordion.Content>
9 A component library that writes source files into your repo.
10 </Accordion.Content>
11 </Accordion.Item>
12 <Accordion.Item value="price">
13 <Accordion.Trigger>Is it free?</Accordion.Trigger>
14 <Accordion.Content>
15 Yes. MIT-licensed. Copy and ship.
16 </Accordion.Content>
17 </Accordion.Item>
18 </Accordion>
19 )
20}

Step 3 — Customize variants and chevron icon

Because the Accordion lives in your codebase, customization is a source edit rather than a prop API. Open src/components/ui/accordion.tsx and look for the const styles object near the top — it holds every class name the component uses. Change styles.trigger for the trigger hover state, styles.panel for the animation timing, or swap the ChevronDown import for any other Lucide icon to change the visual indicator. The theming page lists every color token the Accordion reads from, so you can override them globally in src/styles/globals.scss to re-theme every accordion instance at once. To allow multiple items open simultaneously, pass the multiple prop on the root; pair it with defaultValue={["a", "b"]} to pre-open a subset on mount.

1// src/components/ui/accordion.tsx — top of file
2import { ChevronDown } from 'lucide-react' // swap for Plus, Minus, etc.
3
4const styles = {
5 base: 'w-full divide-y divide-border border-y border-border',
6 trigger: cn(
7 'flex items-center justify-between w-full py-4',
8 'text-sm font-medium text-foreground',
9 'hover:text-foreground/80 transition-colors cursor-pointer'
10 ),
11 icon: cn(
12 'w-4 h-4 text-muted-foreground',
13 'transition-transform duration-200'
14 ),
15 panel: 'grid transition-[grid-template-rows] duration-200',
16 content: 'overflow-hidden text-sm text-muted-foreground',
17}

Step 4 — Wire keyboard and ARIA expectations

Drivn's Accordion triggers are native <button> elements, which gives you keyboard Tab focus, Enter and Space to toggle, and form-safe click handling for free. The component emits aria-expanded on each trigger and wraps content in a role="region" container, so screen readers announce collapsed and expanded states correctly. For long lists of accordion items where Arrow-key navigation between triggers is expected — an accessibility audit often flags this for help centers with thirty or more panels — Drivn does not implement a roving tabindex out of the box. Users Tab through each trigger in document order instead. If Arrow-key cycling is a hard requirement for your audience, the shadcn/ui comparison walks through what Radix offers at the cost of bundling the Radix runtime.

Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

Follow Drivn updates
New components, improvements, and guides every release.
Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

Frequently asked questions

Yes. Set your CRA project up with TypeScript and Tailwind v4 first, then run the Drivn CLI. Tailwind v4 has its own short install guide, and making sure a tsconfig.json is present is enough for the CLI to drop the .tsx component into place. The accordion file has no dependencies on React Router, Next.js routing, or any framework-specific API — it renders anywhere React and Tailwind render to the DOM.

Not out of the box. The component's default styles live in Tailwind class strings — without a Tailwind build step those classes do nothing at runtime. If your project uses another CSS system, replace the class strings in the styles object with your own class names or inline styles. The animation and state logic will continue to work; only the visual layer needs a port from Tailwind utilities to your preferred CSS tool.

Copy-and-own components avoid two problems with traditional npm packages: breaking upgrades that change internal APIs, and the lock-in of not being able to edit internals. With Drivn you can adjust the animation timing, change a default variant, or fix a bug in five seconds without opening a PR upstream. The trade-off is that upgrades are manual — you choose when and whether to pull new CLI versions and re-run the install command.

Yes. The component has no position constraints and can render inside any container that supports arbitrary children. A common pattern is an FAQ accordion inside a feedback dialog, or an options list inside a mobile drawer. The internal focus and keyboard handling adapt to the parent automatically — Tab navigation flows naturally from the surrounding elements into the accordion triggers and back out without extra configuration.