Summit
ComponentsLayout

Collapsible

A Collapsible allows users to show and hide one section of content by clicking its trigger.

When to Use

  • to keep the rest of a short list out of the way, such as the second and third line items of an invoice
  • to cut a long message short, such as a Bubble with a “Show the full message” Button under it

When Not to Use

  • for several sections under their own headings (use an Accordion)
  • for content that floats over the page (use a Popover)
  • for views where one is always shown (use Tabs)

See Accordion for a comparison of the Accordion and the Collapsible.

Anatomy

3 line items
Design, 12 hours
Development, 30 hours
Project management, 4 hours
ElementUsage
RootRequired
TriggerRequired
PanelRequired

A Collapsible has no styles of its own. The root is a div, and the trigger is a button with no classes, so pass a Button to the trigger through render. You can place the trigger anywhere inside the root, before the panel or after it.

DoPass a Button to the trigger through render so that it looks like a control.
Don’tWhen the trigger has no classes, it looks like a line of text, so users can’t tell that a click shows the other line items.

States

To disable the trigger, set disabled on Collapsible. A disabled trigger has aria-disabled in place of the disabled attribute, so it stays in the tab order, and it ignores clicks.

Behavior

By default, a Collapsible is closed. While it is closed, the panel isn’t in the page’s markup. When the panel opens, it pushes down the content that follows it.

Hidden Content

To keep the closed panel in the markup with the hidden attribute, set keepMounted on CollapsibleContent. If you set hiddenUntilFound, the panel is hidden with hidden="until-found", so the browser’s find-in-page reaches its text and opens the panel.

Accessibility

Base UI’s Collapsible renders the trigger as a native button and reports the panel’s state on it.

Requirements

A trigger that contains only an icon has no text. It needs an aria-label so that screen readers can announce it, as WCAG 2.2 SC 4.1.2 Name, Role, Value requires.

The label of the trigger stays the same when the panel opens, and aria-expanded reports the state. If you want to change the words, control open from the parent, as in Change the Label When Open.

Installation

npx shadcn@latest add @summit/collapsible

Usage

import { Button } from '@/components/ui/button';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible';

<Collapsible>
    <CollapsibleContent>The calendar needs a way to pick a time zone.</CollapsibleContent>
    <CollapsibleTrigger render={<Button variant="link" size="sm" />}>Show the full message</CollapsibleTrigger>
</Collapsible>;

Start Open

To open the panel initially, set defaultOpen on Collapsible.

Start Open
<Collapsible defaultOpen>
    <CollapsibleTrigger render={<Button variant="ghost" size="sm" />}>Line items</CollapsibleTrigger>
    <CollapsibleContent>Development, 30 hours</CollapsibleContent>
</Collapsible>

Change the Label When Open

To change the label when the panel opens, control the state from the parent with open and onOpenChange on Collapsible, and choose the label there.

Change the Label When Open
import { useState } from 'react';

const [open, setOpen] = useState(false);

<Collapsible open={open} onOpenChange={setOpen}>
    <CollapsibleContent>The calendar needs a way to pick a time zone.</CollapsibleContent>
    <CollapsibleTrigger render={<Button variant="link" size="sm" />}>
        {open ? 'Show less' : 'Show the full message'}
    </CollapsibleTrigger>
</Collapsible>;

API Reference

Summit adds no props. The parts accept the props of their matching parts in Base UI’s Collapsible, where CollapsibleContent is Collapsible.Panel. See the Base UI Collapsible documentation for open, defaultOpen, onOpenChange, disabled, keepMounted, and hiddenUntilFound.

On this page