Skip to content

Commit 9fd69a2

Browse files
authored
feat(Disclosure): new component (#906)
1 parent 400dbfd commit 9fd69a2

File tree

10 files changed

+1846
-35
lines changed

10 files changed

+1846
-35
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@cube-dev/ui-kit': minor
3+
---
4+
5+
Add new `Disclosure` component for expandable/collapsible content sections. Features include:
6+
7+
- `Disclosure` - Single expandable panel with trigger and content
8+
- `Disclosure.Trigger` - Built on ItemButton with full support for icons, descriptions, and actions
9+
- `Disclosure.Content` - Collapsible content area with smooth height animations
10+
- `Disclosure.Group` - Accordion container for multiple disclosures with single or multiple expanded support
11+
- `Disclosure.Item` - Individual item within a group
12+
13+
Supports controlled/uncontrolled state, `shape` variants (`default`, `card`, `sharp`), disabled state, custom transition duration, and render prop API for custom triggers.
14+
Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
import { Meta, Canvas, Story, Controls } from '@storybook/addon-docs/blocks';
2+
import { Disclosure } from './Disclosure';
3+
import * as DisclosureStories from './Disclosure.stories';
4+
5+
<Meta of={DisclosureStories} />
6+
7+
# Disclosure
8+
9+
An accessible collapsible container that reveals or hides additional content. Built on React Aria's `useDisclosure` hook, it provides keyboard navigation, screen reader support, and smooth height animations. Supports both standalone usage and grouped accordion behavior.
10+
11+
## When to Use
12+
13+
- For FAQ sections where users can expand answers to questions
14+
- To hide supplementary information that shouldn't overwhelm the main content
15+
- For accordion-style navigation or settings panels
16+
- When you need collapsible sections with consistent accessibility patterns
17+
- To progressively disclose complex information
18+
19+
## Component
20+
21+
<Story of={DisclosureStories.SingleDisclosure} />
22+
23+
---
24+
25+
### Properties
26+
27+
<Controls of={DisclosureStories.SingleDisclosure} />
28+
29+
### Base Properties
30+
31+
Supports [Base properties](/BaseProperties)
32+
33+
## Compound Components
34+
35+
### Disclosure.Trigger
36+
37+
The clickable button that toggles the disclosure. Built on `ItemButton` and accepts all ItemButton props including `icon`, `type`, `theme`, `size`, and more.
38+
39+
### Disclosure.Content
40+
41+
The collapsible panel containing the hidden content. Animates smoothly using CSS `interpolate-size: allow-keywords` for height transitions.
42+
43+
### Disclosure.Group
44+
45+
Container for multiple disclosure items that coordinates their expanded states. By default, only one item can be expanded at a time (accordion behavior).
46+
47+
<Story of={DisclosureStories.GroupDisclosure} />
48+
49+
### Disclosure.Item
50+
51+
Individual disclosure within a group. Must have a unique `id` prop when used inside `Disclosure.Group`.
52+
53+
## Styling
54+
55+
### styles
56+
57+
Customizes the root element of the Disclosure component.
58+
59+
### triggerStyles
60+
61+
When using `Disclosure.Trigger`, you can pass `styles` prop to customize the trigger button.
62+
63+
### contentStyles
64+
65+
When using `Disclosure.Content`, you can pass `styles` prop to customize the content panel.
66+
67+
### Group-level Styling
68+
69+
`Disclosure.Group` accepts `triggerProps` to apply consistent props to all triggers, and `contentStyles` to style all content panels uniformly.
70+
71+
### Style Properties
72+
73+
Direct style application without using the `styles` prop: `width`, `height`, `padding`, `margin`, `gap`.
74+
75+
### Modifiers
76+
77+
The `mods` property accepts the following modifiers:
78+
79+
| Modifier | Type | Description |
80+
|----------|------|-------------|
81+
| `expanded` | `boolean` | True when the disclosure content is visible |
82+
| `disabled` | `boolean` | True when interactions are disabled |
83+
| `shape` | `string` | The current shape variant (`default`, `card`, `sharp`) |
84+
85+
For `Disclosure.Content`, additional modifiers are available:
86+
87+
| Modifier | Type | Description |
88+
|----------|------|-------------|
89+
| `shown` | `boolean` | True when content is visible (controls height animation) |
90+
| `phase` | `string` | Transition phase (`enter`, `entered`, `exit`, `unmounted`) |
91+
92+
## Variants
93+
94+
### Shapes
95+
96+
#### Card
97+
98+
Bordered container with rounded corners.
99+
100+
<Story of={DisclosureStories.CardShape} />
101+
102+
#### Sharp
103+
104+
Sharp edges with no border radius.
105+
106+
<Story of={DisclosureStories.SharpShape} />
107+
108+
## Examples
109+
110+
### Default Expanded
111+
112+
Disclosure that starts in expanded state using `defaultExpanded` prop.
113+
114+
<Story of={DisclosureStories.DefaultExpanded} />
115+
116+
### Disabled
117+
118+
Disabled disclosure that cannot be toggled.
119+
120+
<Story of={DisclosureStories.Disabled} />
121+
122+
### Controlled State
123+
124+
Control the disclosure state externally with `isExpanded` and `onExpandedChange`.
125+
126+
<Story of={DisclosureStories.Controlled} />
127+
128+
### Multiple Expanded Items
129+
130+
Group with `allowsMultipleExpanded` where multiple items can be open simultaneously.
131+
132+
<Story of={DisclosureStories.MultipleExpanded} />
133+
134+
### Default Expanded Keys
135+
136+
Group with specific items pre-expanded via `defaultExpandedKeys`.
137+
138+
<Story of={DisclosureStories.DefaultExpandedKeys} />
139+
140+
### Custom Trigger with Render Prop
141+
142+
Use render prop pattern to create custom triggers with access to `isExpanded` and `toggle`.
143+
144+
<Story of={DisclosureStories.RenderProp} />
145+
146+
### Disabled Group
147+
148+
Group-level `isDisabled` that disables all items at once.
149+
150+
<Story of={DisclosureStories.DisabledGroup} />
151+
152+
### Nested Disclosures
153+
154+
Disclosures can be nested, each maintaining independent state.
155+
156+
<Story of={DisclosureStories.Nested} />
157+
158+
## Accessibility
159+
160+
### Keyboard Navigation
161+
162+
- `Tab` - Moves focus to the disclosure trigger
163+
- `Space` / `Enter` - Toggles the disclosure open/closed
164+
- `Tab` (when expanded) - Moves focus into the content panel
165+
166+
### Screen Reader Support
167+
168+
- Trigger announces as a button with expanded/collapsed state
169+
- `aria-expanded` is automatically managed by React Aria
170+
- `aria-controls` links trigger to content panel automatically
171+
- State changes are announced when toggling
172+
173+
### ARIA Properties
174+
175+
- `aria-expanded` - Indicates whether content is visible (managed automatically)
176+
- `aria-controls` - Links trigger to panel (managed automatically)
177+
- `aria-disabled` - Applied when `isDisabled` is true
178+
179+
## Best Practices
180+
181+
1. **Do**: Provide clear, descriptive trigger labels
182+
183+
```jsx
184+
<Disclosure.Trigger>View shipping details</Disclosure.Trigger>
185+
```
186+
187+
2. **Don't**: Use vague or icon-only triggers without labels
188+
189+
```jsx
190+
<Disclosure.Trigger>+</Disclosure.Trigger>
191+
```
192+
193+
3. **Do**: Use groups for related collapsible sections
194+
195+
```jsx
196+
<Disclosure.Group>
197+
<Disclosure.Item id="billing">...</Disclosure.Item>
198+
<Disclosure.Item id="shipping">...</Disclosure.Item>
199+
</Disclosure.Group>
200+
```
201+
202+
4. **Accessibility**: Always ensure trigger text clearly indicates what will be revealed
203+
204+
5. **Performance**: Content remains mounted during transitions for smooth animations and accessibility
205+
206+
## Related Components
207+
208+
- [ItemButton](/docs/actions-itembutton--docs) - The base component used for triggers
209+
- [DisplayTransition](/docs/helpers-displaytransition--docs) - Manages animation phases

0 commit comments

Comments
 (0)