Skip to content

Commit a3bfad7

Browse files
committed
feat(ExpandableSection): allow function toggleContent
Signed-off-by: gitdallas <[email protected]>
1 parent 2d7afac commit a3bfad7

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

packages/react-core/src/components/ExpandableSection/ExpandableSection.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ export interface ExpandableSectionProps extends Omit<React.HTMLProps<HTMLDivElem
4444
* use the onToggle property of the expandable section toggle sub-component.
4545
*/
4646
onToggle?: (event: React.MouseEvent, isExpanded: boolean) => void;
47-
/** React node that appears in the attached toggle in place of the toggleText property. */
48-
toggleContent?: React.ReactNode;
47+
/** React node that appears in the attached toggle in place of the toggleText property.
48+
* Can also be a function that receives the expanded state and returns a React node.
49+
*/
50+
toggleContent?: React.ReactNode | ((isExpanded: boolean) => React.ReactNode);
4951
/** Text that appears in the attached toggle. */
5052
toggleText?: string;
5153
/** Text that appears in the attached toggle when collapsed (will override toggleText if
@@ -246,6 +248,9 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
246248
propOrStateIsExpanded
247249
);
248250

251+
const computedToggleContent =
252+
typeof toggleContent === 'function' ? toggleContent(propOrStateIsExpanded) : toggleContent;
253+
249254
const expandableToggle = !isDetached && (
250255
<div className={`${styles.expandableSection}__toggle`}>
251256
<Button
@@ -265,7 +270,7 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
265270
aria-label={toggleAriaLabel}
266271
aria-labelledby={toggleAriaLabelledBy}
267272
>
268-
{toggleContent || computedToggleText}
273+
{computedToggleContent || computedToggleText}
269274
</Button>
270275
</div>
271276
);

packages/react-core/src/components/ExpandableSection/__tests__/ExpandableSection.test.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,37 @@ test('Renders with aria-labelledby when toggleAriaLabelledBy is passed', () => {
208208

209209
expect(screen.getByRole('button')).toHaveAccessibleName('Test label');
210210
});
211+
test('Renders toggleContent as a function in uncontrolled mode (collapsed)', () => {
212+
render(
213+
<ExpandableSection toggleContent={(isExpanded) => (isExpanded ? 'Hide details' : 'Show details')}>
214+
Test content
215+
</ExpandableSection>
216+
);
217+
218+
expect(screen.getByRole('button', { name: 'Show details' })).toBeInTheDocument();
219+
});
220+
221+
test('Renders toggleContent as a function in uncontrolled mode (expanded after click)', async () => {
222+
const user = userEvent.setup();
223+
224+
render(
225+
<ExpandableSection toggleContent={(isExpanded) => (isExpanded ? 'Hide details' : 'Show details')}>
226+
Test content
227+
</ExpandableSection>
228+
);
229+
230+
const button = screen.getByRole('button', { name: 'Show details' });
231+
await user.click(button);
232+
233+
expect(screen.getByRole('button', { name: 'Hide details' })).toBeInTheDocument();
234+
});
235+
236+
test('Renders toggleContent as a function in controlled mode', () => {
237+
render(
238+
<ExpandableSection isExpanded={true} toggleContent={(isExpanded) => (isExpanded ? 'Collapse' : 'Expand')}>
239+
Test content
240+
</ExpandableSection>
241+
);
242+
243+
expect(screen.getByRole('button', { name: 'Collapse' })).toBeInTheDocument();
244+
});

0 commit comments

Comments
 (0)