@wordpress/ui: add Collapsible component#76280
Conversation
|
Size Change: 0 B Total Size: 8.75 MB ℹ️ View Unchanged
|
|
Flaky tests detected in 6076f97. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/22820275747
|
There was a problem hiding this comment.
Pull request overview
This PR adds a standalone Collapsible component to @wordpress/ui that wraps Base UI's Collapsible.Root, Collapsible.Trigger, and Collapsible.Panel as thin pass-through wrappers. It also refactors the existing CollapsibleCard component to consume this new Collapsible wrapper instead of importing Base UI directly, establishing a proper layered architecture between primitives and higher-level components.
Changes:
- Introduces
Collapsible.Root,Collapsible.Trigger, andCollapsible.Panelcomponents withforwardRefsupport, types, tests, and Storybook stories - Refactors
CollapsibleCard(root, header, content) to use the newCollapsiblewrapper instead of importing@base-ui/react/collapsibledirectly - Exports the new
Collapsiblenamespace from the package entry point
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
packages/ui/src/collapsible/root.tsx |
New Root component wrapping Base UI's Collapsible.Root |
packages/ui/src/collapsible/trigger.tsx |
New Trigger component wrapping Base UI's Collapsible.Trigger |
packages/ui/src/collapsible/panel.tsx |
New Panel component wrapping Base UI's Collapsible.Panel |
packages/ui/src/collapsible/types.ts |
Type definitions for Root, Trigger, and Panel using ComponentProps |
packages/ui/src/collapsible/index.ts |
Barrel export for the three sub-components |
packages/ui/src/collapsible/test/index.test.tsx |
Comprehensive tests covering uncontrolled/controlled usage, ref forwarding, render props, disabled state, and className |
packages/ui/src/collapsible/stories/index.story.tsx |
Storybook stories demonstrating default, open, disabled, and controlled variants |
packages/ui/src/index.ts |
Adds Collapsible namespace export |
packages/ui/src/collapsible-card/root.tsx |
Switches from Base UI import to Collapsible wrapper |
packages/ui/src/collapsible-card/header.tsx |
Switches to Collapsible wrapper; changes icon state check from state.open to aria-expanded attribute |
packages/ui/src/collapsible-card/content.tsx |
Switches from Base UI import to Collapsible wrapper |
packages/ui/CHANGELOG.md |
Documents the new Collapsible primitive |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
mirka
left a comment
There was a problem hiding this comment.
Not necessary for merging this PR, but highlighting the hiddenUntilFound behavior in a story seems useful. In fact that might be a feature we would need to support in CollapsibleCard too.
| // The Collapsible wrapper's `render` prop | ||
| // uses a single-argument callback (via the | ||
| // ComponentProps utility), so Base UI's | ||
| // second `state` argument isn't available | ||
| // here. We derive the open state from | ||
| // `aria-expanded` instead of `state.open`. | ||
| icon={ | ||
| props[ 'aria-expanded' ] === true | ||
| ? chevronUp | ||
| : chevronDown | ||
| } |
There was a problem hiding this comment.
At this point I think it's definitely cleaner to use a single svg and rotate it in CSS based on the [aria-expanded]. What do you think?
Thin wrapper around Base UI's Collapsible component with Root, Trigger, and Panel subcomponents. No custom styles — this is a pure pass-through of the Base UI API. Made-with: Cursor
Covers default, default-open, disabled, and controlled variants. Made-with: Cursor
Covers ref forwarding, uncontrolled/controlled open state, disabled behavior, and className pass-through. Made-with: Cursor
Made-with: Cursor
- Fix import ordering: external (@base-ui) before @WordPress - Add render prop tests for Root, Trigger, and Panel Made-with: Cursor
Replace direct @base-ui/react/collapsible imports with the new internal Collapsible component in all three CollapsibleCard files. In header.tsx, derive the open state from the aria-expanded prop instead of the Base UI state callback, since our wrapper's render prop type uses a single-argument signature. Made-with: Cursor
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
The Collapsible wrapper's ComponentProps utility narrows the render callback to a single-argument signature, so Base UI's `state` object isn't available. Document why we read open state from `aria-expanded`. Made-with: Cursor
6076f97 to
b9d7fcc
Compare
|
e2e test failures don't seem related to the changes in this PR |
What?
Add a
Collapsiblecomponent to@wordpress/ui, wrapping Base UI's Collapsible.Why?
We're building a new set of UI primitives (see #71196). The
CollapsibleCardcomponent (#76252) already wraps Base UI's Collapsible internally — this PR exposesCollapsibleas a standalone primitive so consumers can compose their own collapsible UIs without needing the Card chrome.How?
Thin pass-through wrapper around Base UI's
Collapsible.Root,Collapsible.Trigger, andCollapsible.Panel. No custom styles, no omitted props — the full Base UI API is available.Testing Instructions
npm run test:unit -- packages/ui/src/collapsible/test/index.test.tsxnpm run storybook:dev, then navigate to Design System / Components / CollapsibleMade with Cursor