Expandable Container
Expandable shows and hides information to create a focused experience.
Anatomy

- Chevron Icon: This is part of the header to indicate the opened or closed state of the container. This icon could be placed on the left or right side of the header. When the chevron is on the left of the Title, it shows Chevron Right for ‘collapsed’ and Chevron Down for ‘expanded.’ When the chevron is on the right of the Title, it shows Chevron Down for ‘collapsed’ and Chevron Up for ‘expanded.’
- Avatar Indicator (Optional): This is used to display a user photo for containers that are user related. If there is no user photo available, it shows the default user icon.
- Title: The heading text for the information being shown in the content section.
- Content Section: This section is where users can find more information and details about the container’s subject.
Usage Guidance
- This component highlights the most important details of a section and reveals more when a user taps or clicks on the header part of the container.
- Enabling users to hide and show information ensures the design remains focused and relevant to their expectations.
- Scanning through the most critical information first makes processing more efficient without compromising the ability to access additional information.
When to Use
Use an Expandable Container when there is a lot of information to be shown on a page, but some details can initially be hidden from view.
When to Use Something Else
Be cautious of hiding critical information or burdening the user with an extra click if they are likely to read all the content. There is a chance that content hidden within the collapsed state will not be read or immediately noticed by users.
Design Annotations Needed
- Specify the heading level for the Expandable Container title
Examples
Start Icon
For a basic expandable container with a chevron icon before the title, placeExpandable.Icon before
Expandable.Title as children of Expandable.Target and pass the iconPosition prop to
Expandable.Icon with a value of start. Expandable.Icon will use a right chevron icon when
collapsed and a down chevron icon when expanded.
import {Expandable} from '@workday/canvas-kit-react/expandable';
export default () => (
<Expandable>
<Expandable.Target headingLevel="h4">
<Expandable.Icon iconPosition="start" />
<Expandable.Title>Title</Expandable.Title>
</Expandable.Target>
<Expandable.Content>Content</Expandable.Content>
</Expandable>
);
End Icon
For an expandable container with a chevron icon after the title, place Expandable.Title before
Expandable.Icon as children of Expandable.Target and pass the iconPosition prop to
Expandable.Icon with a value of end. Expandable.Icon will use a down chevron icon when
collapsed and an up chevron icon when expanded.
import {Expandable} from '@workday/canvas-kit-react/expandable';
export default () => (
<Expandable>
<Expandable.Target headingLevel="h4">
<Expandable.Title>
TitleTitleTitleTitleTitle TitleTitleTitleTitle TitleTitleTitle Title
</Expandable.Title>
<Expandable.Icon iconPosition="end" />
</Expandable.Target>
<Expandable.Content>Content</Expandable.Content>
</Expandable>
);
With Avatar
To include an avatar image, Expandable.Avatar should be placed between Expandable.Icon and
Expandable.Title. An iconPosition prop with a value of either start or end should be passed
to Expandable.Icon depending on whether the Expandable.Icon is placed before or after
Expandable.Title.
import {Expandable} from '@workday/canvas-kit-react/expandable';
// @ts-ignore: Cannot find module error
import testAvatar from './test-avatar.png';
export default () => (
<div>
<Expandable>
<Expandable.Target headingLevel="h4">
<Expandable.Icon iconPosition="start" />
<Expandable.Avatar name="Avatar" url={testAvatar} />
<Expandable.Title>Title</Expandable.Title>
</Expandable.Target>
<Expandable.Content>Content</Expandable.Content>
</Expandable>
<Expandable>
<Expandable.Target headingLevel="h4">
<Expandable.Avatar name="Avatar" url={testAvatar} />
<Expandable.Title>Title</Expandable.Title>
<Expandable.Icon iconPosition="end" />
</Expandable.Target>
<Expandable.Content>Content</Expandable.Content>
</Expandable>
</div>
);
Accessibility Note: In this situation, the Avatar is decorative and should not be announced to screen readers. The
<Expandable.Avatar>component hasisDecorativeset totrueby default to hide it from screen readers, as avatars in expandable headers are typically decorative when paired with adjacent text.
Right to Left (RTL)
Expandable container has bidirectional support and should function as expected with RTL languages as long as the content direction is set in your Canvas theme.
import {Expandable} from '@workday/canvas-kit-react/expandable';
import {CanvasProvider} from '@workday/canvas-kit-react/common';
export default () => {
return (
<CanvasProvider dir="rtl">
<Expandable>
<Expandable.Target headingLevel="h4">
<Expandable.Icon iconPosition="start" />
<Expandable.Avatar name="Avatar" />
<Expandable.Title>Title</Expandable.Title>
</Expandable.Target>
<Expandable.Content>Content</Expandable.Content>
</Expandable>
<Expandable>
<Expandable.Target headingLevel="h4">
<Expandable.Avatar name="Avatar" />
<Expandable.Title>Title</Expandable.Title>
<Expandable.Icon iconPosition="end" />
</Expandable.Target>
<Expandable.Content>Content</Expandable.Content>
</Expandable>
</CanvasProvider>
);
};
Depth
The depth prop passed to Expandable allows you to adjust the visual elevation of a component
using our depth tokens.
import {Expandable} from '@workday/canvas-kit-react/expandable';
export default () => {
return (
<Expandable borderRadius="l" depth={3} margin="xxxs" padding="xs">
<Expandable.Target headingLevel="h4">
<Expandable.Title>Additional Information</Expandable.Title>
<Expandable.Icon iconPosition="end" />
</Expandable.Target>
<Expandable.Content>This Expandable Container has a depth of 3.</Expandable.Content>
</Expandable>
);
};
Title Wrap
Long titles will wrap to the next line and increase the height of the container.
import {Expandable} from '@workday/canvas-kit-react/expandable';
// @ts-ignore: Cannot find module error
import testAvatar from './test-avatar.png';
export default () => (
<Expandable>
<Expandable.Target headingLevel="h4">
<Expandable.Icon iconPosition="start" />
<Expandable.Avatar name="Avatar" url={testAvatar} />
<Expandable.Title>
Our house special supreme pizza includes pepperoni, sausage, bell peppers, mushrooms,
onions, and oregano.
</Expandable.Title>
</Expandable.Target>
<Expandable.Content>Content</Expandable.Content>
</Expandable>
);
You can also have direct access to the model if
Hoisted Model
If you need direct access to the model, you can hoist it with the useExpandableModel hook. In the
example below, we’re hoisting the models to expand and collapse all three containers at once.
import React from 'react';
import {Expandable, useExpandableModel} from '@workday/canvas-kit-react/expandable';
import {Flex} from '@workday/canvas-kit-react/layout';
import {SecondaryButton} from '@workday/canvas-kit-react/button';
import {useUniqueId} from '@workday/canvas-kit-react/common';
import {createStyles} from '@workday/canvas-kit-styling';
import {system} from '@workday/canvas-tokens-web';
const listStyles = createStyles({
flexDirection: 'column',
gap: system.space.x2,
padding: system.space.zero,
marginX: system.space.x4,
marginY: system.space.zero,
});
export default () => {
const modelOne = useExpandableModel();
const modelTwo = useExpandableModel();
const modelThree = useExpandableModel();
const idOne = useUniqueId();
const idTwo = useUniqueId();
const idThree = useUniqueId();
const handleExpandAll = () => {
modelOne.events.show();
modelTwo.events.show();
modelThree.events.show();
};
const handleCollapseAll = () => {
modelOne.events.hide();
modelTwo.events.hide();
modelThree.events.hide();
};
return (
<Flex gap={system.space.x6} flexDirection="column">
<Flex gap={system.space.x4}>
<SecondaryButton onClick={handleExpandAll}>Expand All</SecondaryButton>
<SecondaryButton onClick={handleCollapseAll}>Collapse All</SecondaryButton>
</Flex>
<Flex flexDirection="column">
<Expandable model={modelOne}>
<Expandable.Target headingLevel="h4">
<Expandable.Title id={idOne}>Usage Guidance</Expandable.Title>
<Expandable.Icon iconPosition="end" />
</Expandable.Target>
<Expandable.Content as="section" aria-labelledby={idOne}>
This component highlights the most important details of a section and reveals more when
a user taps or clicks on the header part of the container. Enabling users to hide and
show information ensures the design remains focused and relevant to their expectations.
Scanning through the most critical information first makes processing more efficient
without compromising the ability to access additional information.
</Expandable.Content>
</Expandable>
<Expandable model={modelTwo}>
<Expandable.Target headingLevel="h4">
<Expandable.Title id={idTwo}>Accessibility Guidelines</Expandable.Title>
<Expandable.Icon iconPosition="end" />
</Expandable.Target>
<Expandable.Content as="section" aria-labelledby={idTwo}>
<Flex as="ul" cs={listStyles}>
<li>
The state of a component being open or closed must be conveyed to assistive
technologies.
</li>
<li>A Button must be used as the control to toggle the display of any content.</li>
<li>
If there are multiple toggle Buttons on the same page, provide additional
information in their labels to make them uniquely distinguishable to a screen
reader.
</li>
<li>
Do not change the toggle Button label to convey state. An exception to this would be
a scenario where a visual hint text is decoupled from both the state and the label
for a control so the hint text is not announced by assistive technologies.
</li>
<li>
Avoid keyboard traps when adding components to the accordion panel. For example, the
user expands an accordion, but is unable to tab to the next focusable element.
</li>
<li>
Hidden content must be hidden correctly from keyboard, screen reader, and touch
interaction.
</li>
<li>
Changing the label of something to indicate its state will not always be accounted
for in live time for a screen reader user. For example, a play button should have a
non-changing, persistent label and the state (pressed or unpressed) is conveyed
visually as well as to assistive technology once the state is changed.
</li>
</Flex>
</Expandable.Content>
</Expandable>
<Expandable model={modelThree}>
<Expandable.Target headingLevel="h4">
<Expandable.Title id={idThree}>Content Guidelines</Expandable.Title>
<Expandable.Icon iconPosition="end" />
</Expandable.Target>
<Expandable.Content as="section" aria-labelledby={idThree}>
Titles should be short and concise, yet long enough to explain what the user would
expect to see when the content is expanded. If titles must be long, make sure it doesn't
wrap more than two lines.
</Expandable.Content>
</Expandable>
</Flex>
</Flex>
);
};
Accessibility Note: When using multiple Expandable Containers on a page, use the
asprop to render the<Expandable.Content>sub-component as an HTML<section>element. Then, usearia-labelledbyto reference the uniqueidof the<Expandable.Title>element. This practice can be useful to screen reader users when multiple Expandable Containers are opened at one time for uniquely describing the boundaries of the expandable content.
Accessibility
Our Expandable component renders a semantic HTML <button> element to the DOM, with an optional
parent heading element as defined by the headingLevel prop. The aria-expanded property is
included on the button to indicate the state of the content to screen readers.
Accordion Pattern | APG | WAI | W3C
- Use the
headingLevelprop to assign an appropriate heading level based on the context of the page content. - When using Expandable Container for navigation elements, then we don’t recommend using the
headingLevelprop. This will render only expandable buttons to the DOM, reserving headings for organizing content in the main body of the page. - The
asprop may also be used on<Expandable.Content>to render an HTML<ul>element for displaying a list of items. For example, check out Side Panel with Navigation.
Navigation
- Tab key: Moves focus to the next expandable button or focusable element
- Shift + Tab: Moves focus to the previous focusable element
- Enter or Space: Toggles the expanded/collapsed state
Screen Reader Experience
- The expandable button will be announced with its title text followed by the button role
- The current state will be announced as either “collapsed” or “expanded” (For example: “Usage Guidance, button, collapsed” or “Usage Guidance, button, expanded”)
- State Changes: When activating the button to expand content, screen readers will announce the new “expanded” state and vice versa when collapsing content.
- Content Regions: Screen reader users can use landmark navigation to jump between sections and each section will be announced with its associated title (For example: “Usage Guidance, landmark region”)
- Heading Structure: Using heading levels with expandable buttons allows screen reader users to navigate by headings, making the document structure and hierarchy easier to understand.
Component API
Expandable
Expandable wraps an Expandable.Target and an Expandable.Content. By default, it provides a
DisclosureModel for its subcomponents. Alternatively, a model may be passed in using the
hoisted model pattern.
Layout Component
Expandable supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
Props extend from . If a model is passed, props from ExpandableModelConfig are ignored.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The children of the | |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Expandable.Target
Expandable.Target creates a heading and a button. The heading is a semantic heading to
describe the associated content. The button provides users the ability to toggle the
associated content.
As according to the W3 disclosure
specification, the button has
aria-expanded and aria-controls attributes set by default
This component should hold an Expandable.Icon, an optional Expandable.Avatar, and an
Expandable.Title.
Layout Component
Expandable.Target supports all props from thelayout component.
Props
Props extend from button. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | Children of the | |
headingLevel | | This specifies the semantic heading level that will wrap the | |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | button |
ref | React.Ref<R = button> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useExpandableTarget
(
model: ,
elemProps: {},
ref: React.Ref
) => {
aria-controls: string;
aria-expanded: boolean;
onClick: (event: ) => void;
}Expandable.Title
Expandable.Title styles the target text that describes the content.
Layout Component
Expandable.Title supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | Children of the | |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If |
Expandable.Icon
Expandable.Icon creates an icon to visually indicate the state of the content. It takes an
iconPosition prop to determine which chevron icon to use.
Layout Component
Expandable.Icon supports all props from thelayout component.
Props
Props extend from span. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
icon | | Icon to display from | |
iconPosition | | Button icon positions can either be | 'start' |
size | number | string | The size of the SystemIcon in | |
fill | string | The fill color of the SystemIcon. This overrides | |
background | string | The background color of the SystemIcon. | |
color | string | The color of the SystemIcon. This defines | |
shouldMirror | boolean | If set to | false |
shouldMirrorInRTL | boolean | If set to | false |
cs | | The | |
children | ReactNode | ||
accent | string | The accent color of the SystemIcon. This overrides | |
accentHover | string | The accent color of the SystemIcon on hover. This overrides | |
backgroundHover | string | The background color of the SystemIcon on hover. | |
colorHover | string | The hover color of the SystemIcon. This defines | |
fillHover | string | The fill color of the SystemIcon on hover. This overrides | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | span |
ref | React.Ref<R = span> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
Expandable.Avatar
Expandable.Avatar is an optional component that creates an Avatar to display a decorative
image.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
url | string | The URL of the user's photo. For best fit, use square images. | |
objectFit | Property.ObjectFit | An objectFit property that can customize how to resize your image to fit its container. | 'contain' |
isDecorative | boolean | If true, the Avatar won't forward the | true |
children | ReactNode | Children of the BaseAvatar. | |
variant | | The variant of the Avatar. | 'blue' |
size | | The size of the Avatar.
| 'medium' |
cs | | The | |
name | string | The alt text of the Avatar image. This prop is also used for the initials. The first letter of the first name and the first letter of the second name are chosen for the initials. | '' |
preferredInitials | string | If you want full control over the initials, use | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If |
Expandable.Content
Expandable.Content holds the content that will be conditionally expanded and collapsed. It
has an id to ensure the Expandable.Target properly set it to the aria-controls
attribute.
Layout Component
Expandable.Content supports all props from thelayout component.
Props
Props extend from div. Changing the as prop will change the element interface.
| Name | Type | Description | Default |
|---|---|---|---|
children | ReactNode | The children of the | |
cs | | The | |
as | React.ElementType | Optional override of the default element used by the component. Any valid tag or Component. If you provided a Component, this component should forward the ref using Note: Not all elements make sense and some elements may cause accessibility issues. Change this value with care. | div |
ref | React.Ref<R = div> | Optional ref. If the component represents an element, this ref will be a reference to the real DOM element of the component. If | |
model | | Optional model to pass to the component. This will override the default model created for the component. This can be useful if you want to access to the state and events of the model, or if you have nested components of the same type and you need to override the model provided by React Context. | |
elemPropsHook | ( | Optional hook that receives the model and all props to be applied to the element. If you use this, it is your responsibility to return props, merging as appropriate. For example, returning an empty object will disable all elemProps hooks associated with this component. This allows finer control over a component without creating a new one. |
useExpandableContent
(
model: ,
elemProps: {},
ref: React.Ref
) => {
style: {
display: undefined;
} | {
display: string;
};
id: string;
}Model
useExpandableModel
The ExpandableModel extends the DisclosureModel
useExpandableModel (config: ): How Expandable Containers Impact the Accessible Experience
Any pattern that can show and hide content in a design must support the non-visual screen reading experience. Users must be able to perceive whether the content is expanded or collapsed, and users need to know where they can find the new expanded content.
The reading order of the expanded content must logically follow the target button controlling the content’s visibility for non-visual users to find and understand the content change. A non-visual screen reading experience is fundamentally linear, like reading a book.
Content Guidelines
- Titles should be short and concise, yet long enough to explain what the user would expect to see when the content is expanded.
- If titles must be long, make sure it doesn’t wrap more than two lines.
Anatomy

- Leading Element (Optional): Avatar or System Icon.
- Sub-Label (Optional): Additional text area for displaying further information in the header.
- Divider (Optional): Used to separate container from other content.
- Dynamic Body: Flexible body slot that expands and collapses.
- Chevron: Dynamic system icon indicating collapsed and expanded states of the body content.
- Container: Houses all elements.
- Badge (Optional): Represents quantitative information centered against the Label and Sub-Label.
- Label: Main header text.
Usage Guidance
Expandable hides information that may not be needed right away. Tapping on the header shows or hides content.
Collapsed content which is hidden by default should not be needed by users right away. Hiding needed actions or information critical to completion of a task can lead to user frustration.

Do
Use Expandable to hide non-critical information that may not be needed immediately.

Don't
Hide critical information or actions in the content area.
Progressive Disclosure
Elements within the header should hint at the content to follow, so that users can make an informed choice about whether or not they want to see more details.
When to Use
Expandables are helpful to declutter a UI and focus user attention on more important details. Use an Expandable to:
- Hide content that isn’t needed right away, but may be helpful in a certain context.
- Keep an interface clutter-free and more manageable. If the amount of content on the screen is making it difficult to consume, consider hiding some of that content.
- Keep users in their current view, while remaining in context of a larger idea. Instead of navigating to another screen, Expandables help keep additional details directly related to the current screen.
When to Consider Something Else
- For tasks that require scanning and comparison, Lists better enable users to see more content at once. Having to expand and collapse separate containers to compare information can slow down and frustrate users.
- For folder or tree navigation, use a List with a trailing rightward chevron to redirect elsewhere. Expandables are used to show and hide content on the same screen — not for navigation.
- If action is required from the user to move along in a flow, consider surfacing that action using a Bottom Sheet or Alert Dialog instead. Avoid hiding tasks necessary for progression within an Expandable, as it may get lost.
Behaviors
Touch Targets
The entire surface area of the header is interactive. Tapping on the header expands or collapses the content area, showing or hiding more details. Elements within the header do not have an additional touch target. Elements contained in expandable content area may have their own touch targets.

Do
Keep a parallel structure for the tap target.

Don't
Enable touch targets for individual elements within the header, such as with Avatar.
States
Expandables support the default, pressed, and selected states in their headers, including when the container is expanded.

Examples
Trailing Chevron
By default, the container displays as collapsed. After pressing on the header, content expands outwards from the container, with the chevron rotating 180 degrees clockwise.

Leading Chevron
On larger screens like tablets, the icon is placed in the leading area of the container before any visuals or the label to prevent a large space between content and the affordance for expanding and collapsing. During expansion, the chevron rotates clockwise 90 degrees.

Optional Elements
Avatar
An Avatar may be placed in the leading area before the label.
![]()
Icon
A leading system icon may also be placed in the leading area before the label.
![]()
Badge
Badge may be used within Expandable to convey numerical information associated with the data being represented by the header.

Sub-Label
A sub-label may be used to supplement the main label in the header.

In Cards
Expandables may be used within Card for additional hierarchy and visual emphasis in the UI. Card can contain multiple or a single instance of Expandable.

Wrapping
Text does not automatically truncate in Expandable, so the main label and sub-label should ideally never exceed 3 lines of text.
Truncation may be set at any number of lines in both the main label and sub-label for closed Expandables. When open, however, all text will display, even if truncation has been set for the closed version.
Component API
Methods
Class name: ExpandableContainer Module name: UIComponentsPlugin
public init(
featureData: FeatureMetricsData,
title: String,
subtitle: String? = nil,
isExpanded: Bool = false,
leadingItem: ExpandableContainerLeadingItem? = nil,
badgeCount: Int? = nil,
titleLineLimit: Int? = nil,
subtitleLineLimit: Int? = nil,
semanticContext: State<SemanticContext> = .init(initialValue: .default),
removePaddingOnHeader: Bool = false,
showDivider: Bool = true,
contentSpacing: CGFloat? = nil,
localizer: LocalizationAdapting,
@ViewBuilder content: @escaping () -> Content
)Parameters
| Name | Type | Default | Description |
|---|---|---|---|
| featureData | FeatureMetricsData | The feature name/context and the screen ID in which the component appears | |
| title | String | The written title to display for the header of the container | |
| isExpanded | Bool | False | Optional Bool for the expansion state. This allows you to set whether you want the container expanded on startup or not. Expansion state is then managed by the container itself. |
| leadingItem | ExpandableContainerLeadingItem | nil | Optional ExpandableContainerLeadingItem allows you to display an image or a standard avatar in the header. |
| badgeCount | Int? | nil | Optional Int to display a badge with the count in the header of the container |
| titleLineLimit | Int? | nil | Optional Int to limit the lines used for the title in the collapsed version of the container |
| subtitleLineLimit | Int? | nil | Optional Int to limit the lines used for the subtitle in the collapsed version of the container |
| semanaticContext | SemanticContext | .default | Managed SemanticContext of the state for the entire container. Default is to let expandable container handle it itself. This allows for enabling, disabling, warning, error, and required states. |
| removePaddingOnHeader | Bool | false | Optional bool which will override the padding in the header. Default is false |
| showDivider | Bool | true | Optional bool that can show the divider underneath the container. Default is true |
| localizer | LocalizationAdapting | Localization provider | |
| content | @ViewBuilder content: @escaping () -> Content | @ViewBuilder closure for the content you want displayed inside the container. | |
Content Guidelines
When writing content for an Expandable, please refer to the Expandable section of Content’s UI Text recommendations.
Anatomy

- Leading Element (Optional): Avatar or System Icon.
- Sub-Label (Optional): Additional text area for displaying further information in the header.
- Divider (Optional): Used to separate container from other content.
- Dynamic Body: Flexible body slot that expands and collapses.
- Chevron: Dynamic system icon indicating collapsed and expanded states of the body content.
- Container: Houses all elements.
- Badge (Optional): Represents quantitative information centered against the Label and Sub-Label.
- Label: Main header text.
Usage Guidance
Expandable hides information that may not be needed right away. Tapping on the header shows or hides content.
Collapsed content which is hidden by default should not be needed by users right away. Hiding needed actions or information critical to completion of a task can lead to user frustration.

Do
Use Expandable to hide non-critical information that may not be needed immediately.

Don't
Hide critical information or actions in the content area.
Progressive Disclosure
Elements within the header should hint at the content to follow, so that users can make an informed choice about whether or not they want to see more details.
When to Use
Expandables are helpful to declutter a UI and focus user attention on more important details. Use an Expandable to:
- Hide content that isn’t needed right away, but may be helpful in a certain context.
- Keep an interface clutter-free and more manageable. If the amount of content on the screen is making it difficult to consume, consider hiding some of that content.
- Keep users in their current view, while remaining in context of a larger idea. Instead of navigating to another screen, Expandables help keep additional details directly related to the current screen.
When to Consider Something Else
- For tasks that require scanning and comparison, Lists better enable users to see more content at once. Having to expand and collapse separate containers to compare information can slow down and frustrate users.
- For folder or tree navigation, use a List with a trailing rightward chevron to redirect elsewhere. Expandables are used to show and hide content on the same screen — not for navigation.
- If action is required from the user to move along in a flow, consider surfacing that action using a Bottom Sheet or Alert Dialog instead. Avoid hiding tasks necessary for progression within an Expandable, as it may get lost.
Behaviors
Touch Targets
The entire surface area of the header is interactive. Tapping on the header expands or collapses the content area, showing or hiding more details. Elements within the header do not have an additional touch target. Elements contained in expandable content area may have their own touch targets.

Do
Keep a parallel structure for the tap target.

Don't
Enable touch targets for individual elements within the header, such as with Avatar.
States
Expandables support the default, pressed, and selected states in their headers, including when the container is expanded.

Examples
Trailing Chevron
By default, the container displays as collapsed. After pressing on the header, content expands outwards from the container, with the chevron rotating 180 degrees clockwise.

Leading Chevron
On larger screens like tablets, the icon is placed in the leading area of the container before any visuals or the label to prevent a large space between content and the affordance for expanding and collapsing. During expansion, the chevron rotates clockwise 90 degrees.

Optional Elements
Avatar
An Avatar may be placed in the leading area before the label.
![]()
Icon
A leading system icon may also be placed in the leading area before the label.
![]()
Badge
Badge may be used within Expandable to convey numerical information associated with the data being represented by the header.

Sub-Label
A sub-label may be used to supplement the main label in the header.

In Cards
Expandables may be used within Card for additional hierarchy and visual emphasis in the UI. Card can contain multiple or a single instance of Expandable.

Wrapping
Text does not automatically truncate in Expandable, so the main label and sub-label should ideally never exceed 3 lines of text.
Truncation may be set at any number of lines in both the main label and sub-label for closed Expandables. When open, however, all text will display, even if truncation has been set for the closed version.
Component API
@Composable
fun ExpandableContainerUiComponent(
modifier: Modifier = Modifier,
label: String,
avatarConfig: ExpandableContainerAvatarConfig? = null,
semanticState: SemanticState = SemanticState(),
initiallyExpanded: Boolean = false,
onExpandedStateChange: (expanded: Boolean) -> Unit = {},
content: @Composable () -> Unit = {}
)Props
| Name | Type | Default | Description |
|---|---|---|---|
| label | String | None | Text shown on the expandable container. |
| avatarConfig | ExpandableContainerAvatarConfig | null | Optional avatar config for the container. Will only be used in the normal semantic state. |
| semanticState | SemanticState | SemanticState() | Adjusts the state of the Component. This allows for enabling, disabling, warning, error, and required states. |
| initiallyExpanded | Boolean | false | Initial expanded state of the container. Defaults to collapsed. |
| onExpandedStateChange | (expanded: Boolean) -> Unit | Optional lambda to execute when we expand or collapse the container. | |
| content | @Composable () -> Unit | Content slot for content that shows up below the title when expanded. |
Content Guidelines
When writing content for an Expandable, please refer to the Expandable section of Content’s UI Text recommendations.
Can't Find What You Need?
Check out our FAQ section which may help you find the information you're looking for. For further information, contact the #ask-canvas-design or #ask-canvas-kitchannels on Slack.