Collapsible
One disclosure, rendered as <details>.
import { Collapsible } from '@apostel/bedrock'
// or, to drive it from React: import { Collapsible } from '@apostel/bedrock/controlled'
Sourcecollapsible.tsx
import { Collapsible } from '../../src/index'
/**
* A single `<details>`. Unlike Dialog the root *is* the element, because
* `<summary>` only works as a child of `<details>` — so there is nothing to
* wire by id and `defaultOpen` is a plain attribute rather than an imperative
* call on mount.
*/
export default function CollapsibleDemo() {
return (
<Collapsible.Root style={{ width: '100%', maxWidth: '28rem' }}>
<Collapsible.Trigger>Delivery details</Collapsible.Trigger>
<Collapsible.Content>
Ships from Rotterdam. Tracked, and signed for over €50.
</Collapsible.Content>
</Collapsible.Root>
)
}Anatomy
<Collapsible.Root>
<Collapsible.Trigger />
<Collapsible.Content />
</Collapsible.Root>
Collapsible.Root
Renders <details data-bedrock-collapsible>.
| prop | type | notes |
|---|---|---|
defaultOpen |
boolean |
Read once; the attribute does the rest. |
onOpenChange |
(open: boolean) => void |
Reports; cannot refuse. |
asChild |
boolean |
The child must render a <details>. |
For an open prop React drives, import from @apostel/bedrock/controlled.
That direction only: <details> has no cancelable hook, so onOpenChange
cannot decline a toggle there either. To stop one, preventDefault() the
Trigger's click. Both are on controlled state.
openis read on the first render only. React writes a DOM property when the value it renders changes, so reading it once means the user's own toggling is never undone by an unrelated re-render.
Collapsible.Trigger
Renders <summary>. It carries the expanded state itself, so there is no
aria-expanded to write and no button to keep in step.
Collapsible.Content
Renders a <div>. Children mount only while open, so a form inside a closed
panel resets itself when it closes.
Server-rendered markup is the exception: content renders on the server and on the hydrating render that must match it. A page whose JavaScript never arrives still has a complete, working disclosure. There is a test that loads it with scripting disabled and toggles it.
What is not here
- Height animation.
<details>has no interoperable height transition yet. See styling for what does work. disabled. Not a native concept on<details>.Accordion.Itemoffersdata-disabledas the closest thing; this does not.