Display

Accordion.

Stacked questions that open one panel at a time, with a rotating chevron and orange open state.

A small web for Minecraft servers. In-game computers serve pages, and the hub lists every site on the network.

Installation#

With the CLI

$npx lanterncn add accordion

This also installs the Lantern theme and any Lantern UI components it depends on. The shadcn CLI works directly too: npx shadcn@latest add httptim/lantern-ui/accordion. See Installation if your project is not set up yet.

Manually

  1. Install the dependencies

    npm install radix-ui lucide-react
  2. Copy the source into your project

    components/ui/accordion.tsx
    "use client";
    
    import * as React from "react";
    import { ChevronDownIcon } from "lucide-react";
    import { Accordion as AccordionPrimitive } from "radix-ui";
    
    import { cn } from "@/lib/utils";
    
    function Accordion({ ...props }: React.ComponentProps<typeof AccordionPrimitive.Root>) {
      return <AccordionPrimitive.Root data-slot="accordion" {...props} />;
    }
    
    function AccordionItem({ className, ...props }: React.ComponentProps<typeof AccordionPrimitive.Item>) {
      return <AccordionPrimitive.Item data-slot="accordion-item" className={cn("border-b last:border-b-0", className)} {...props} />;
    }
    
    function AccordionTrigger({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Trigger>) {
      return (
        <AccordionPrimitive.Header className="flex">
          <AccordionPrimitive.Trigger
            data-slot="accordion-trigger"
            className={cn(
              "flex flex-1 cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left font-display text-base font-medium tracking-tight transition-colors outline-none hover:text-primary focus-visible:ring-2 focus-visible:ring-ring/25 disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-primary [&[data-state=open]>svg]:rotate-180",
              className,
            )}
            {...props}
          >
            {children}
            <ChevronDownIcon
              aria-hidden="true"
              className="pointer-events-none mt-0.5 size-4 shrink-0 text-muted-foreground transition-transform duration-200"
            />
          </AccordionPrimitive.Trigger>
        </AccordionPrimitive.Header>
      );
    }
    
    function AccordionContent({ className, children, ...props }: React.ComponentProps<typeof AccordionPrimitive.Content>) {
      return (
        <AccordionPrimitive.Content
          data-slot="accordion-content"
          className="overflow-hidden text-sm text-muted-foreground data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
          {...props}
        >
          <div className={cn("pt-0 pb-4 leading-relaxed", className)}>{children}</div>
        </AccordionPrimitive.Content>
      );
    }
    
    export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
  3. Update the import paths to match your project

    The source imports cn from @/lib/utils.

Usage#

import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from "@/components/ui/accordion";
<Accordion type="single" collapsible>
  <AccordionItem value="a">
    <AccordionTrigger>What is Lantern?</AccordionTrigger>
    <AccordionContent>A small web for Minecraft servers.</AccordionContent>
  </AccordionItem>
</Accordion>