Collapsible

Collapsible is a component that shows or hides content.

Give FeedbackWAI-ARIABundle Size

This is the collapsed content. The element that shows and hides the content has role button

When the content is visible, the element with role `button` has `aria-expanded` set to `true`

When the content panel is hidden, it is set to `false`

Installation

Base UI components are all available as a single package.

npm install @base-ui-components/react

Once you have the package installed, import the component.

import { Collapsible } from '@base-ui-components/react/Collapsible';

Anatomy

<Collapsible.Root>
  <Collapsible.Trigger>Toggle</Collapsible.Trigger>
  <Collapsible.Panel>This is the content</Collapsible.Panel>
</Collapsible.Root>

Improving searchability of hidden content

This is not yet supported in Safari and Firefox as of August 2024 and will fall back to the default hidden behavior.

Content hidden in the Collapsible.Panel component can be made accessible only to a browser's find-in-page functionality with the hiddenUntilFound prop to improve searchability:

<Collapsible.Root defaultOpen={false}>
  <Collapsible.Trigger>Toggle</Collapsible.Trigger>
  <Collapsible.Panel hiddenUntilFound>
    When this component is closed, this sentence will only be accessible to the browser's native
    find-in-page functionality
  </Collapsible.Panel>
</Collapsible.Root>

We recommend using CSS animations for animated collapsibles that use this feature. Currently there is browser bug that does not highlight the found text inside elements that have a CSS transition applied.

This relies on the HTML hidden="until-found" attribute which only has partial browser support as of August 2024, but automatically falls back to the default hidden state in unsupported browsers.

Animations

Animation states

Three states are available as data attributes to animate the Collapsible:

The component can be animate when opening or closing using either:

Styling

The Collapsible.Panel element receives the following CSS variables about its dimensions, which can be used to style animations or transitions:

CSS Animations

CSS animations can be used with two declarations:

.CollapsiblePanel {
  overflow: hidden;
  animation: slideUp 300ms ease-in;
}

.CollapsiblePanel[data-open] {
  animation: slideDown 300ms ease-out;
}

@keyframes slideDown {
  from {
    height: 0;
  }
  to {
    height: var(--collapsible-panel-height);
  }
}

@keyframes slideUp {
  from {
    height: var(--collapsible-panel-height);
  }
  to {
    height: 0;
  }
}

This is the collapsed content

You can find the Base UI repository here

This is a longer sentence and also the third paragraph

CSS Transitions

When using CSS transitions, styles for the Panel must be applied to three states:

.CollapsiblePanel {
  overflow: hidden;
  /* The final styles once closed/exited  */
  height: 0;
  transition: height 300ms ease-in;
}

/* The final styles once opened/entered */
.CollapsiblePanel[data-open] {
  height: var(--collapsible-panel-height);
  transition: height 300ms ease-out;
}

/* The initial styles when opening/entering */
.CollapsiblePanel[data-entering] {
  height: 0;
}

This is the collapsed content.

You can find the Base UI repository here.

This is a longer sentence and also the third paragraph.

JavaScript Animations

When using external libraries for animation, for example framer-motion, be aware that Collapsible hides content using the HTML hidden attribute in the closed state, and does not unmount the Collapsible.Panel subcomponent.

function App() {
  const [open, setOpen] = useState(false);
  return (
    <Collapsible.Root open={open} onOpenChange={setOpen}>
      <Collapsible.Trigger>Toggle</Collapsible.Trigger>
      <Collapsible.Panel
        render={
          <motion.div
            key="CollapsiblePanel"
            initial={false}
            animate={open ? 'open' : 'closed'}
            exit={!open ? 'open' : 'closed'}
            variants={{
              open: {
                height: 'auto',
                transition: { duration: 0.6, ease: 'ease-out' },
              },
              closed: {
                height: 0,
                transition: { duration: 0.6, ease: 'ease-in' },
                transitionEnd: { display: 'revert-layer' },
              },
            }}
          />
        }
      >
        This is the content
      </Collapsible.Panel>
    </Collapsible.Root>
  );
}

Overriding default components

Use the render prop to override the rendered elements with your own components. The Collapsible.Root component does not render an element to the DOM by default, but can do so with the render prop:

// Element shorthand
<Collapsible.Root render={<MyCollapsibleRoot />} />
// Function
<Collapsible.Root render={(props) => <MyCollapsibleRoot {...props} />} />

API Reference

CollapsibleRoot

PropTypeDefaultDescription
animatedbooltrueIf true, the component supports CSS/JS-based animations and transitions.
classNameunionClass names applied to the element or a function that returns them based on the component's state.
defaultOpenbooltrueIf true, the Collapsible is initially open. This is the uncontrolled counterpart of open.
disabledboolfalseIf true, the component is disabled.
onOpenChangefuncCallback fired when the Collapsible is opened or closed.
openboolIf true, the Collapsible is initially open. This is the controlled counterpart of defaultOpen.
renderunionA function to customize rendering of the component.

CollapsibleTrigger

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
renderunionA function to customize rendering of the component.

CollapsiblePanel

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
hiddenUntilFoundboolfalseIf true, sets hidden="until-found" when closed. If false, sets hidden when closed.
renderunionA function to customize rendering of the component.

Contents