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

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>
  );
}

Angular edition planned for Phase 5h. Star the repo to track progress.

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

<Collapsible>
  <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">
    Hidden bio content.
  </CollapsibleContent>
</Collapsible>

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

Gremorie ships 100 primitives across 9 React packages.

<p>
  Gremorie ships 100 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