Skip to contents

Collapsible

A collapsible panel controlled by a button.

import type { JSX } from '@solidjs/web';
import { Collapsible } from 'base-ui-solid/collapsible';
import styles from './index.module.css';

export default function ExampleCollapsible() {
  return (
    <Collapsible.Root class={styles.Collapsible}>
      <Collapsible.Trigger class={styles.Trigger}>
        Recovery keys
        <CaretRightIcon class={styles.Icon} />
      </Collapsible.Trigger>
      <Collapsible.Panel class={styles.Panel}>
        <div class={styles.Content}>
          <div>alien-bean-pasta</div>
          <div>wild-irish-burrito</div>
          <div>horse-battery-staple</div>
        </div>
      </Collapsible.Panel>
    </Collapsible.Root>
  );
}

export function CaretRightIcon(props: JSX.IntrinsicElements['svg']) {
  return (
    <svg
      width="16"
      height="16"
      viewBox="0 0 16 16"
      fill="currentColor"
      {...props}
      style={{ display: 'block' }}
    >
      <path d="M6 12V4l4.5 4z" />
    </svg>
  );
}

Anatomy

Import the component and assemble its parts:

Anatomy
import { Collapsible } from 'base-ui-solid/collapsible';

<Collapsible.Root>
  <Collapsible.Trigger />
  <Collapsible.Panel />
</Collapsible.Root>;

Examples

Hidden until found

The hiddenUntilFound prop hides the closed panel with hidden="until-found" so the browser can search its contents with find-in-page—Ctrl+F (Cmd+F on macOS)—and reveal the panel when a match is found. The closed panel always remains mounted in the DOM, which also makes its contents indexable by search engines.

Older browsers that don’t support hidden="until-found" keep the panel hidden until its trigger opens it, and find-in-page skips over the contents.

Searchable hidden panel
<Collapsible.Root>
  <Collapsible.Trigger>Shipping details</Collapsible.Trigger>
  <Collapsible.Panel hiddenUntilFound>Standard shipping takes 3–5 business days.</Collapsible.Panel>
</Collapsible.Root>

See the Accordion example for an interactive demo.

API reference

Root

Groups all parts of the collapsible. Renders a <div> element.

Prop
Type
Default
defaultOpenbooleanfalse
Whether the collapsible panel is initially open. To render a controlled collapsible, use the open prop instead.boolean
openboolean—
Whether the collapsible panel is currently open. To render an uncontrolled collapsible, use the defaultOpen prop instead.boolean
onOpenChangefunction—
Event handler called when the panel is opened or closed.((open: boolean, eventDetails: Collapsible.Root.ChangeEventDetails) => void)
disabledbooleanfalse
Whether the component should ignore user interaction.boolean
classfunction—
CSS class applied to the element, or a function that returns a class based on the component’s state.JSX.ClassValue | ((state) => JSX.ClassValue)
stylefunction—
Style applied to the element, or a function that returns a style object based on the component’s state.JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)
renderfunction—
Replace the default element with a tag name, component, or render function.keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)

Data attributes

Name
Type
Default
data-open-—
Present when the collapsible is open.-
data-closed-—
Present when the collapsible is closed.-
data-starting-style-—
Present when the collapsible begins animating in.-
data-ending-style-—
Present when the collapsible is animating out.-
Attribute
Description
data-open
Present when the collapsible is open.
data-closed
Present when the collapsible is closed.
data-starting-style
Present when the collapsible begins animating in.
data-ending-style
Present when the collapsible is animating out.
Root.State
type CollapsibleRootState = {
  /** Whether the collapsible panel is currently open. */
  open: boolean;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  transitionStatus: TransitionStatus;
};
Root.ChangeEventReason
type CollapsibleRootChangeEventReason = 'trigger-press' | 'none';
Root.ChangeEventDetails
type CollapsibleRootChangeEventDetails = (
  | { reason: 'trigger-press'; event: MouseEvent | PointerEvent | TouchEvent | KeyboardEvent }
  | { reason: 'none'; event: Event }
) & {
  /** Cancels Base UI from handling the event. */
  cancel: () => void;
  /** Allows the event to propagate in cases where Base UI will stop the propagation. */
  allowPropagation: () => void;
  /** Indicates whether the event has been canceled. */
  isCanceled: boolean;
  /** Indicates whether the event is allowed to propagate. */
  isPropagationAllowed: boolean;
  /** The element that triggered the event, if applicable. */
  trigger: Element | undefined;
};

Trigger

A button that opens and closes the collapsible panel. Renders a <button> element.

Prop
Type
Default
nativeButtonbooleantrue
Whether the component renders a native <button> element when replacing it via the render prop. Set to false if the rendered element is not a button (for example, <div>).boolean
classfunction—
CSS class applied to the element, or a function that returns a class based on the component’s state.JSX.ClassValue | ((state) => JSX.ClassValue)
stylefunction—
Style applied to the element, or a function that returns a style object based on the component’s state.JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)
renderfunction—
Replace the default element with a tag name, component, or render function.keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)

Data attributes

Name
Type
Default
data-panel-open-—
Present when the collapsible panel is open.-
Attribute
Description
data-panel-open
Present when the collapsible panel is open.
Trigger.State
type CollapsibleTriggerState = {
  /** Whether the collapsible panel is currently open. */
  open: boolean;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
  transitionStatus: TransitionStatus;
};

Panel

A panel with the collapsible contents. Renders a <div> element.

Prop
Type
Default
hiddenUntilFoundbooleanfalse
Allows the browser’s built-in page search to find and expand the panel contents. Overrides the keepMounted prop and uses hidden="until-found" to hide the element without removing it from the DOM.boolean
classfunction—
CSS class applied to the element, or a function that returns a class based on the component’s state.JSX.ClassValue | ((state) => JSX.ClassValue)
stylefunction—
Style applied to the element, or a function that returns a style object based on the component’s state.JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)
keepMountedbooleanfalse
Whether to keep the element in the DOM while the panel is hidden. This prop is ignored when hiddenUntilFound is used.boolean
renderfunction—
Replace the default element with a tag name, component, or render function.keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)

Data attributes

Name
Type
Default
data-open-—
Present when the collapsible panel is open.-
data-closed-—
Present when the collapsible panel is closed.-
data-starting-style-—
Present when the panel begins animating in.-
data-ending-style-—
Present when the panel is animating out.-
Attribute
Description
data-open
Present when the collapsible panel is open.
data-closed
Present when the collapsible panel is closed.
data-starting-style
Present when the panel begins animating in.
data-ending-style
Present when the panel is animating out.

CSS variables

Name
Type
Default
--collapsible-panel-heightnumber—
The collapsible panel’s height.number
--collapsible-panel-widthnumber—
The collapsible panel’s width.number
CSS Variable
Description
--collapsible-panel-height
The collapsible panel’s height.
--collapsible-panel-width
The collapsible panel’s width.
Panel.State
type CollapsiblePanelState = {
  /** The transition status of the component. */
  transitionStatus: TransitionStatus;
  /** Whether the collapsible panel is currently open. */
  open: boolean;
  /** Whether the component should ignore user interaction. */
  disabled: boolean;
};