Components
Accordion

Accordion

An interactive collection of stacked headings that reveal individual content sections with a click.

Yes. It has a dark mode that can be toggled in the settings. Dark mode is designed to reduce eye strain, especially in low-light environments.

How it works

Install the following dependencies:

pnpm add @radix-ui/react-accordion lucide-react tailwind-merge clsx

Create a new file at lib/utils.ts and add the provided code.

import clsx, { ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cn(...inputs: ClassValue[]) {
    return twMerge(clsx(inputs));
}

Create a file at components/ui/accordion.tsx and paste the given code.

accordion.tsx

"use client";
 
import * as React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDown } from "lucide-react";
 
import { cn } from "@/lib/utils";
 
const Accordion = AccordionPrimitive.Root;
 
const AccordionItem = React.forwardRef<
    React.ComponentRef<typeof AccordionPrimitive.Item>,
    React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
>(({ className, ...props }, ref) => (
    <AccordionPrimitive.Item
        ref={ref}
        className={cn("border-b dark:border-neutral-800", className)}
        {...props}
    />
));
AccordionItem.displayName = "AccordionItem";
 
const AccordionTrigger = React.forwardRef<
    React.ComponentRef<typeof AccordionPrimitive.Trigger>,
    React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
    <AccordionPrimitive.Header className="flex">
        <AccordionPrimitive.Trigger
            ref={ref}
            className={cn(
                "flex flex-1 items-center justify-between py-4 text-left text-sm font-medium transition-all [&[data-state=open]>svg]:rotate-180",
                className,
            )}
            {...props}
        >
            {children}
            <ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
        </AccordionPrimitive.Trigger>
    </AccordionPrimitive.Header>
));
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName;
 
const AccordionContent = React.forwardRef<
    React.ComponentRef<typeof AccordionPrimitive.Content>,
    React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
>(({ className, children, ...props }, ref) => (
    <AccordionPrimitive.Content
        ref={ref}
        className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
        {...props}
    >
        <div className={cn("pb-4 pt-0", className)}>{children}</div>
    </AccordionPrimitive.Content>
));
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
 
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };

Import and use the Accordion component in your application.

import {
    Accordion,
    AccordionContent,
    AccordionItem,
    AccordionTrigger,
} from "@/components/ui/accordion";
 
const items = [
    {
        id: "1",
        title: "Is cnippet/ui accessible?",
        content:
            "Yes. It adheres to the WAI-ARIA design pattern, making it accessible for users with disabilities. It also supports screen readers and other assistive technologies.",
    },
    {
        id: "2",
        title: "Does cnippet/ui have a dark mode?",
        content:
            "Yes. It has a dark mode that can be toggled in the settings. Dark mode is designed to reduce eye strain, especially in low-light environments.",
    },
    {
        id: "3",
        title: "Is cnippet/ui responsive?",
        content:
            "Yes. It's fully responsive and works seamlessly across devices with different screen sizes, from mobile phones to large desktop monitors.",
    },
];
 
export default function AccordionDemo() {
    return (
        <div className="max-w-lg space-y-4">
            <Accordion
                type="single"
                collapsible={false}
                className="w-full"
                defaultValue="2"
            >
                {items.map((item) => (
                    <AccordionItem
                        value={item.id}
                        key={item.id}
                        className="py-2"
                    >
                        <AccordionTrigger className="py-2 text-sm leading-6 hover:no-underline">
                            {item.title}
                        </AccordionTrigger>
                        <AccordionContent className="pb-2 text-muted-foreground">
                            {item.content}
                        </AccordionContent>
                    </AccordionItem>
                ))}
            </Accordion>
        </div>
    );
}

Examples

Default

Yes. It has a dark mode that can be toggled in the settings. Dark mode is designed to reduce eye strain, especially in low-light environments.

W/ plus-minus

Yes. It's fully responsive and works seamlessly across devices with different screen sizes, from mobile phones to large desktop monitors.

W/ icon

Yes. It's fully responsive and works seamlessly across devices with different screen sizes, from mobile phones to large desktop monitors.

Tabs w/ chevron

Yes. It's fully responsive and works seamlessly across devices with different screen sizes, from mobile phones to large desktop monitors.