Klarhimmel UI

Accordion

Stable

A stack of headings that each open and close a panel. One open at a time, or several.

npx shadcn add @klarhimmel/accordion

When to use

  • Use for

    A list of questions or settings groups where people read a few and skip the rest.

  • Not for

    Content everyone must read. Show it. Not for switching views. Use Tabs.

  • Pairs with

    Text, Badge, Card.

Preview

Rooms are ready from 15:00. If you arrive earlier we keep your bags at the desk.

accordion.tsx
import { Theme } from '@/components/klarhimmel/theme/style';
import { Accordion, AccordionItem } from '@/components/klarhimmel/ui/accordion';

export default function Example() {
  return (
    <Theme theme="brand">
      <Accordion defaultValue="checkin">
        <AccordionItem value="checkin" title="When can I check in?">From 15:00.</AccordionItem>
        <AccordionItem value="parking" title="Is there parking?">Yes, behind the building.</AccordionItem>
      </Accordion>
    </Theme>
  );
}

Install

Import

import { Accordion, AccordionItem } from '@/components/klarhimmel/ui/accordion';
Lands in
components/klarhimmel/ui/accordion.tsx, plus cn() and the theme item if they are missing. Import theme.css after Tailwind.
Render in
Render it inside <Theme>, once near the root of your app. Tokens and fonts are scoped to it, so outside it the component is unstyled.

Examples

  • Multiple

    Several panels can stay open at once, and one item is switched off.

    Served 07:00 to 10:00 in the garden room.

    Open 06:00 to 21:00. Towels are in your room.

    import { Accordion, AccordionItem } from '@/components/klarhimmel/ui/accordion';
    
    export default function AccordionMultiple() {
      return (
        <div className="mx-auto flex w-[min(36rem,calc(100cqw-3rem))] flex-col gap-3">
          <p className="text-kh-small text-kh-muted">Several panels can stay open at once, and one item is switched off.</p>
          <Accordion type="multiple" defaultValue={['breakfast', 'spa']}>
            <AccordionItem value="breakfast" title="Breakfast">Served 07:00 to 10:00 in the garden room.</AccordionItem>
            <AccordionItem value="spa" title="Spa">Open 06:00 to 21:00. Towels are in your room.</AccordionItem>
            <AccordionItem value="bike" title="Bike hire" disabled>Closed for the season.</AccordionItem>
            <AccordionItem value="late" title="Late arrival">Call the desk and we leave the key in a box by the door.</AccordionItem>
          </Accordion>
        </div>
      );
    }
  • Controlled

    Twelve rooms on three floors.

    Open: rooms

    import { useState } from 'react';
    import { Accordion, AccordionItem } from '@/components/klarhimmel/ui/accordion';
    import { Button } from '@/components/klarhimmel/ui/button';
    
    export default function AccordionControlled() {
      const [open, setOpen] = useState('rooms');
      return (
        <div className="flex w-[min(36rem,calc(100cqw-3rem))] flex-col gap-3">
          <div className="flex gap-2">
            <Button size="sm" variant="secondary" onClick={() => setOpen('rooms')}>Open rooms</Button>
            <Button size="sm" variant="secondary" onClick={() => setOpen('spa')}>Open spa</Button>
            <Button size="sm" variant="ghost" onClick={() => setOpen('')}>Close all</Button>
          </div>
          <Accordion value={open} onValueChange={setOpen}>
            <AccordionItem value="rooms" title="Rooms">Twelve rooms on three floors.</AccordionItem>
            <AccordionItem value="spa" title="Spa">Sauna, plunge pool and a quiet room.</AccordionItem>
          </Accordion>
          <p role="status" className="text-kh-small text-kh-muted">Open: {open || 'none'}</p>
        </div>
      );
    }

API reference

PropTypeDefaultDescription
type'single' | 'multiple''single'One panel open at a time, or any number.
value / defaultValue / onValueChangestring | string[]-Open item value (a string when single, a list when multiple).
collapsiblebooleantrueSingle mode only. With false the open item cannot be closed.
AccordionItem valuestring-Required. Identifies the item.
AccordionItem titleReactNode-Required. The heading text; it is the button.
AccordionItem level2 | 3 | 4 | 53Heading level, to fit the page outline.
AccordionItem disabledbooleanfalseThe item stays closed and is skipped by the arrow keys.
classNamestring-Extra classes, merged after the component's own.

Accessibility

KeyDoes
Enter / SpaceOpens or closes the focused panel
Down / UpMoves focus to the next or previous heading, wrapping
Home / EndMoves focus to the first or last heading
TabMoves on; closed panels are skipped

Each trigger sits in a heading. Choose its level so the page outline stays correct.

Accessibility