react-collapsible/Examples/Basic toggle
ExamplesStarter

Basic toggle

The smallest useful Collapsible. One useState, one wired button, one panel — with a content fade that runs in sync with the collapse. Copy this file when you need a disclosure and nothing else.

This is the whole pattern: state in the parent, a wired trigger, and a panel that animates open and closed in pure CSS. The text you are reading fades in sync with the collapse, courtesy of the conditional classes.

When to reach for basic-toggle

This is the shape for a single, self-contained disclosure — a "show more" under a teaser, an optional settings block, an explainer panel. Everything lives in one component: the useState that owns the open state, the button that flips it, and the Collapsible that animates it. Because the component is fully controlled, the toggle is yours to replace — swap useState for a store or a URL param and nothing else changes. The moment several panels need to coordinate — open one, close the rest — you've outgrown the single toggle; see the FAQ accordion for that shape.

TSXbasic-toggle.tsx
import { Collapsible } from '@westopp/react-collapsible'
import { useState } from 'react'

// Tailwind note: closed: is a library prefix, not a Tailwind variant, so the
// bare utilities it toggles must appear somewhere Tailwind scans for them to
// be emitted: opacity-0 opacity-100

export const BasicToggle = () => {
const [open, setOpen] = useState(false)

return (
  <div className='rounded-(--radius-callout) border border-(--color-line) bg-(--color-bg-elev) p-5'>
    <button
      type='button'
      aria-controls='basic-toggle-panel'
      aria-expanded={open}
      onClick={() => setOpen(!open)}
      className='cursor-pointer rounded-full bg-(--color-accent) px-[18px] py-[8px] text-[14px] font-medium text-(--color-accent-ink)'
    >
      {open ? 'Hide details' : 'Show details'}
    </button>
    <Collapsible
      id='basic-toggle-panel'
      open={open}
      transitionDuration='300ms'
      className='transition-opacity duration-300 open:opacity-100 closed:opacity-0'
    >
      <p className='pt-4 text-[14px] leading-relaxed text-(--color-ink-soft)'>
        This is the whole pattern: state in the parent, a wired trigger, and a panel that animates open and closed in pure CSS. The text you are reading fades in
        sync with the collapse, courtesy of the conditional classes.
      </p>
    </Collapsible>
  </div>
)
}

What it covers

  • Controlled open state — the parent's useState owns the boolean; Collapsible renders whatever it's handed and holds no state of its own.
  • A wired trigger — the button carries aria-controls matching the panel's id and aria-expanded mirroring the state. Dev builds warn if the wiring is missing.
  • A conditional fadeopen:opacity-100 closed:opacity-0 flip on the same RAF-deferred state that drives the [open] attribute, so the fade transitions in sync with the height animation instead of snapping. The conditional classes page covers the prefixes in full.
  • A comfortable durationtransitionDuration='300ms' overrides the stylesheet's 500ms default, and the fade's duration-300 matches it so nothing trails behind.