Skip to content

Collapsible

Show or hide a section of content from a single control.

import { Collapsible, CollapsibleChevron, CollapsibleContent, CollapsibleTrigger } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use it to keep secondary content out of the way until someone asks for it: advanced settings, the rest of a long list, details under a summary. For a stack of sections, use an Accordion. For content that should float over the page instead of pushing it down, use a Popover.

import { Button, Collapsible, CollapsibleChevron, CollapsibleContent, CollapsibleTrigger } from '@youj/react'

export function AdvancedSettings() {
  return (
    <Collapsible>
      <CollapsibleTrigger render={<Button variant="ghost" size="sm" />}>
        Advanced settings
        <CollapsibleChevron />
      </CollapsibleTrigger>
      <CollapsibleContent>
        <div className="pt-3">…</div>
      </CollapsibleContent>
    </Collapsible>
  )
}

CollapsibleTrigger renders a plain button by default. Compose it with any button through render, as in the Demo story, and it keeps its look while gaining the disclosure behavior. Pass defaultOpen to start open, or open and onOpenChange to control it.

The chevron

CollapsibleChevron is Youj's chevron icon, turned over while its trigger is expanded. It reads aria-expanded from the nearest trigger around it, so it works in any disclosure without wiring: a collapsible, an accordion, a navigation menu or a sidebar group, including triggers composed through render. It mounts in its real state, so an open section doesn't turn over on first paint. size sets it in pixels.

<CollapsibleTrigger>
  Filters
  <CollapsibleChevron size={14} className="text-fg-muted" />
</CollapsibleTrigger>

Reference

Propssize, className (2)

Props

CollapsibleChevron

CollapsibleChevron props
PropType
sizenumber

Rendered size in px.

default 16

16
classNamestring–

Collapsible, CollapsibleTrigger and CollapsibleContent

These pass their props through to Base UI's Collapsible.Root, Collapsible.Trigger and Collapsible.Panel. The ones you'll use most:

PartPropTypeDefault
CollapsibledefaultOpenbooleanfalse
Collapsibleopen, onOpenChangeboolean, (open, details) => void–
Collapsibledisabledbooleanfalse
CollapsibleTriggerrenderReactElement | (props, state) => ReactElement–
CollapsibleContentkeepMountedbooleanfalse
CollapsibleContenthiddenUntilFoundbooleanfalse
MotionPanel, chevron · reduced motion

Motion

Motion tokens
MomentTokens
Panelheight to the measured size, then auto, with a fade
duration.baseease.standard

220ms · cubic-bezier(0.2, 0, 0, 1)

220mscubic-bezier(0.2, 0, 0, 1)
Chevronturns over as the panel opens
spring.snappy

0.2s, bounce 0

0.2s, bounce 0

Reduced motion

The panel opens and closes at once, and the chevron flips without turning.

The panel wears the yj-collapse preset: the height eases between zero and the measured size, then settles on auto so the content can still grow. A toggle mid-way reverses from the current height. The panel clips while it moves, so keep padding and focus rings inside it, as the examples do.

Reduced motion

The section still opens and closes, but at once: no height easing and no fade. The chevron flips without turning.

AccessibilityKeyboard, ARIA, announcements

Accessibility

  • The trigger is a button with aria-expanded, and aria-controls pointing at the panel.
  • Enter and Space toggle it. Closed content is removed from the tab order, and from the document unless you pass keepMounted or hiddenUntilFound.
  • The chevron is decorative. The state is announced through aria-expanded, so a label that changes ("Show 4 more", "Show less") is optional.