Skip to main content
Gremorie

Collapsible

Single-section expandable region. The minimal building block for show-more toggles and inline disclosures.

Overview

Collapsible is the simplest disclosure primitive: one trigger, one panel, one open/closed state. Three parts - Collapsible (Root), CollapsibleTrigger, CollapsibleContent - wrap Radix Collapsible.

Reach for Collapsible when you have one thing that expands: a card's "more details" toggle, a sidebar group's expand/collapse, an inline disclosure inside long copy. When you have multiple coordinated sections that share keyboard navigation and a single-open invariant, use Accordion instead - Accordion is built on the same primitives but coordinates a group.

Preview

'use client';import {  Collapsible,  CollapsibleContent,  CollapsibleTrigger,} from '@gremorie/rx-display';import { Button } from '@gremorie/rx-forms';import { ChevronDown } from 'lucide-react';import { useState } from 'react';export function CollapsiblePreview() {  const [open, setOpen] = useState(false);  return (    <Collapsible open={open} onOpenChange={setOpen} className="w-full max-w-md">      <CollapsibleTrigger asChild>        <Button variant="outline" className="w-full justify-between">          What&apos;s inside Gremorie?          <ChevronDown            className={`size-4 transition-transform ${open ? 'rotate-180' : ''}`}          />        </Button>      </CollapsibleTrigger>      <CollapsibleContent className="mt-2 rounded-md border p-4 text-sm">        100 primitives across 9 React packages and 4 Angular packages, plus the        token engine, registry, and MCP handler.      </CollapsibleContent>    </Collapsible>  );}

Anatomy

Collapsible                  the Radix Root (holds open / onOpenChange)
├─ CollapsibleTrigger        the toggle (pass asChild to use your own button)
└─ CollapsibleContent        the region revealed when open

Installation

bash npx gremorie@latest add rx-collapsible

bash pnpm dlx gremorie@latest add rx-collapsible

bash yarn dlx gremorie@latest add rx-collapsible

bash bunx --bun gremorie@latest add rx-collapsible

Usage

import {
  Collapsible,
  CollapsibleTrigger,
  CollapsibleContent,
} from "@gremorie/rx-display";
import { Button } from "@gremorie/rx-forms";

export function Example() {
  return (
    <Collapsible>
      <CollapsibleTrigger asChild>
        <Button variant="outline">Toggle details</Button>
      </CollapsibleTrigger>
      <CollapsibleContent className="mt-2 rounded-md border p-4 text-sm">
        Hidden content revealed when the trigger fires.
      </CollapsibleContent>
    </Collapsible>
  );
}

The Angular edition of this component ships from source today (see the workbench for the side-by-side); its registry entry is coming next.

API

<Collapsible>

Wraps Radix Collapsible.Root.

PropTypeDefaultDescription
openboolean-Controlled open state.
defaultOpenbooleanfalseUncontrolled default.
onOpenChange(open: boolean) => void-Fires when the open state changes.
disabledbooleanfalsePrevents the trigger from firing.

<CollapsibleTrigger>

The clickable element that toggles the panel. Wraps Radix Collapsible.Trigger.

PropTypeDefaultDescription
asChildbooleanfalseWhen true, renders the immediate child as the trigger (typical pattern: wrap a Button).

When asChild is used, the child receives aria-expanded, aria-controls, and the click handler.

<CollapsibleContent>

The panel that opens and closes. Wraps Radix Collapsible.Content. Exposes the data-state="open" \| "closed" attribute so you can animate via your own CSS or Tailwind keyframes.

The Gremorie CollapsibleContent does not ship default animations - drop in animate-collapsible-down / animate-collapsible-up if you want the standard reveal, or compose your own with data-[state] selectors.

Composition

  1. <Collapsible> owns the open/closed state.
  2. <CollapsibleTrigger> sits inside - typically wrapped around a Button via asChild.
  3. <CollapsibleContent> holds the hidden content. Style it however you like; Radix sets hidden when closed and data-state="open" when open.

The trigger and content can sit at any depth inside the root - Radix Collapsible coordinates via context, not DOM order.

Variations

Show more toggle

Nog is the chief engineer of the Kalvner crew. Implements code, infra, and ships. Backs up before destructive changes. Never commits secrets.
'use client';import {  Collapsible,  CollapsibleContent,  CollapsibleTrigger,} from '@gremorie/rx-display';import { Button } from '@gremorie/rx-forms';import { ChevronDown } from 'lucide-react';export function CollapsibleOpenPreview() {  return (    <Collapsible defaultOpen className="w-full max-w-md">      <CollapsibleTrigger asChild>        <Button variant="outline" className="w-full justify-between">          Show full bio          <ChevronDown className="size-4 transition-transform data-[state=open]:rotate-180" />        </Button>      </CollapsibleTrigger>      <CollapsibleContent className="mt-2 rounded-md border p-4 text-sm text-muted-foreground">        Nog is the chief engineer of the Kalvner crew. Implements code, infra,        and ships. Backs up before destructive changes. Never commits secrets.      </CollapsibleContent>    </Collapsible>  );}

defaultOpen renders the panel expanded on mount. The chevron rotates on data-[state=open] so the trigger reflects the current state. Drop defaultOpen to start collapsed.

Controlled open

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

<Collapsible open={open} onOpenChange={setOpen}>
  <CollapsibleTrigger asChild>
    <Button>{open ? 'Hide' : 'Show'} advanced settings</Button>
  </CollapsibleTrigger>
  <CollapsibleContent>
    <SettingsPanel />
  </CollapsibleContent>
</Collapsible>;

Inline disclosure

<p>
  Gremorie ships 83 primitives.{' '}
  <Collapsible className="inline">
    <CollapsibleTrigger>Show breakdown</CollapsibleTrigger>
    <CollapsibleContent>
      <ul>...</ul>
    </CollapsibleContent>
  </Collapsible>
</p>

Accessibility

  • ARIA: the trigger receives aria-expanded (true/false) and aria-controls pointing at the content panel; the content panel is hidden when closed.
  • Keyboard: Space or Enter on the trigger toggles the panel. Standard <button> semantics when using asChild with a Button.
  • Focus: focus stays on the trigger across toggles. The content is not focus-trapped - readers can Tab through it once open.
  • Animation: use data-[state=open] and data-[state=closed] selectors so reveals honor prefers-reduced-motion via your own keyframes.
  • Disabled state: disabled={true} on the root disables the trigger and removes it from the tab order.
  • Accordion - coordinated multiple disclosures with shared state.
  • Card - typical host for a Collapsible "show more" toggle.
  • Sidebar - uses Collapsible for group expand/collapse.

On this page