Toggle
Simple button to toggle open/closed. Requires using render props to pass a ref to the element that you want Expandable
to animate to/from the height of. The transition status
is also passed as one of the render props, so you can change styling based on the transition state.
Editable example
() => {
const [expanded, setExpanded] = React.useState(false);
return (
<Card>
<div style={{ padding: "var(--space-m)" }}>
<Button onClick={() => setExpanded(!expanded)} aria-expanded={expanded} aria-controls="example-expandable-1">Show/hide</Button>
<Expandable expanded={expanded}>
{({ expandableElementRef, status }) => (
<div id="example-expandable-1" ref={expandableElementRef} style={{ paddingTop: "var(--space-m)" }}>
<Text lineHeight="compact">Here's some toggleable content that expands and contracts as it shows and hides. Pretty neat huh. All you need is a div inside to pass a ref to and it does its thing.</Text>
</div>
)}
</Expandable>
</div>
</Card>
);
}
Dismiss
Expandable also works going in one direction for dismissable content.
Editable example
() => {
const [expanded, setExpanded] = React.useState(true);
return (
<Expandable expanded={expanded}>
{({ expandableElementRef }) => (
<div ref={expandableElementRef}>
<Alert heading="Message name" onDismiss={() => setExpanded(false)}>
<Text lineHeight="compact">Hey, this is a dismissable message</Text>
</Alert>
</div>
)}
</Expandable>
);
}
Timing
Set a different duration using the timeout
prop. Default to AnimationDuration.Medium
.
Editable example
() => {
const [expanded, setExpanded] = React.useState(true);
return (
<Card>
<div style={{ padding: "var(--space-m)" }}>
<Button onClick={() => setExpanded(!expanded)} aria-expanded={expanded} aria-controls="example-expandable-1">Long duration</Button>
<Expandable expanded={expanded} timeout={AnimationDuration.Long}>
{({ expandableElementRef }) => (
<div id="example-expandable-1" ref={expandableElementRef} style={{ paddingTop: "var(--space-m)" }}>
<Text lineHeight="compact">Here's some toggleable content that expands and contracts as it shows and hides. Pretty neat huh. All you need is a div inside to pass a ref to and it does its thing.</Text>
</div>
)}
</Expandable>
</div>
</Card>
);
}
Custom element
Pass a custom element for the element that expands/contracts. This is useful for when the element has a box shadow and including it as a child would cut off the shadow because the expandable element has overflow: hidden;
while animating.
Editable example
() => {
const [expanded, setExpanded] = React.useState(true);
const CardWithShadow = (props) => (
<Card elevation={2} {...props} />
);
return (
<Expandable expanded={expanded} element={CardWithShadow}>
{({ expandableElementRef }) => (
<div ref={expandableElementRef} style={{ display: "grid", gap: "var(--space-m)", padding: "var(--space-m)" }}>
<Text lineHeight="compact">Hey, this is a dismissable message</Text>
<Button onClick={() => setExpanded(false)}>Got it</Button>
</div>
)}
</Expandable>
);
}
Accessibility
Expandable
is generic and doesn't handle any accessibility attributes, so make sure to provide appropriate ones depending on the type of experience you're creating. An accordion will require different roles and attributes to an error message that animates in/out. As a rule of thumb, consult the WAI-ARIA spec for the type of component you're creating.