Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ export interface ExpandableSectionProps extends Omit<React.HTMLProps<HTMLDivElem
* use the onToggle property of the expandable section toggle sub-component.
*/
onToggle?: (event: React.MouseEvent, isExpanded: boolean) => void;
/** React node that appears in the attached toggle in place of the toggleText property. */
toggleContent?: React.ReactNode;
/** React node that appears in the attached toggle in place of the toggleText property.
* Can also be a function that receives the expanded state and returns a React node.
*/
toggleContent?: React.ReactNode | ((isExpanded: boolean) => React.ReactNode);
/** Text that appears in the attached toggle. */
toggleText?: string;
/** Text that appears in the attached toggle when collapsed (will override toggleText if
Expand Down Expand Up @@ -246,6 +248,9 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
propOrStateIsExpanded
);

const computedToggleContent =
typeof toggleContent === 'function' ? toggleContent(propOrStateIsExpanded) : toggleContent;

const expandableToggle = !isDetached && (
<div className={`${styles.expandableSection}__toggle`}>
<Button
Expand All @@ -265,7 +270,7 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
aria-label={toggleAriaLabel}
aria-labelledby={toggleAriaLabelledBy}
>
{toggleContent || computedToggleText}
{computedToggleContent || computedToggleText}
</Button>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,37 @@ test('Renders with aria-labelledby when toggleAriaLabelledBy is passed', () => {

expect(screen.getByRole('button')).toHaveAccessibleName('Test label');
});
test('Renders toggleContent as a function in uncontrolled mode (collapsed)', () => {
render(
<ExpandableSection toggleContent={(isExpanded) => (isExpanded ? 'Hide details' : 'Show details')}>
Test content
</ExpandableSection>
);

expect(screen.getByRole('button', { name: 'Show details' })).toBeInTheDocument();
});

test('Renders toggleContent as a function in uncontrolled mode (expanded after click)', async () => {
const user = userEvent.setup();

render(
<ExpandableSection toggleContent={(isExpanded) => (isExpanded ? 'Hide details' : 'Show details')}>
Test content
</ExpandableSection>
);

const button = screen.getByRole('button', { name: 'Show details' });
await user.click(button);

expect(screen.getByRole('button', { name: 'Hide details' })).toBeInTheDocument();
});

test('Renders toggleContent as a function in controlled mode', () => {
render(
<ExpandableSection isExpanded={true} toggleContent={(isExpanded) => (isExpanded ? 'Collapse' : 'Expand')}>
Test content
</ExpandableSection>
);

expect(screen.getByRole('button', { name: 'Collapse' })).toBeInTheDocument();
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ import CheckCircleIcon from '@patternfly/react-icons/dist/esm/icons/check-circle

```

### Uncontrolled with dynamic toggle content (function)

Use `toggleContent` as a function to dynamically render different content based on the expanded state without managing state yourself.

```ts file="ExpandableSectionUncontrolledDynamicToggleFunction.tsx"

```

### Detached

When passing the `isDetached` property into `<ExpandableSection>`, you must also manually pass in the same `toggleId` and `contentId` properties to both `<ExpandableSection>` and `<ExpandableSectionToggle>`. This will link the content to the toggle via ARIA attributes.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ExpandableSection } from '@patternfly/react-core';

export const ExpandableSectionUncontrolledDynamicToggleFunction: React.FunctionComponent = () => (
<ExpandableSection
toggleContent={(isExpanded) =>
isExpanded
? 'Show less uncontrolled dynamic toggle example content'
: 'Show more uncontrolled dynamic toggle example content'
}
>
This content is visible only when the component is expanded.
</ExpandableSection>
);
Loading