Expandable block
A pattern for progressive disclosure of information.
import * as React from 'react';
import { ExpandableBlock } from '@itwin/itwinui-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock title='Expandable Block'>
Content in block!
</ExpandableBlock>
</div>
);
};
The expandable block has a label reflecting its content. On click, it expands to reveal more content.
Usage
The expandable block can be used in two ways:
- Directly using
ExpandableBlock
along withtitle
,caption
,endIcon
and children. This pattern can suffice for simple cases. - Using subcomponents (
ExpandableBlock.Wrapper
,ExpandableBlock.Trigger
,ExpandableBlock.Content
, etc). This pattern is more verbose but allows full customization over all the parts.
With caption
Descriptor text can be optionally displayed underneath the title, either using the caption
prop or the ExpandableBlock.Caption
subcomponent.
import * as React from 'react';
import { ExpandableBlock } from '@itwin/itwinui-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper size='small'>
<ExpandableBlock.Trigger>
<ExpandableBlock.ExpandIcon />
<ExpandableBlock.LabelArea>
<ExpandableBlock.Title>Expandable Block</ExpandableBlock.Title>
<ExpandableBlock.Caption>With caption!</ExpandableBlock.Caption>
</ExpandableBlock.LabelArea>
</ExpandableBlock.Trigger>
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
Accordion
Expandable blocks can also stack on top of each other in an accordion to make large sets of information easier to read.
import * as React from 'react';
import { ExpandableBlock } from '@itwin/itwinui-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger label='Block #1' />
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger label='Block #2' />
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger label='Block #3' />
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
With status
An expandable block could display status, an icon, or other helpful information at a glance right aligned within the block header. The status can be set using the status
prop, and the icon can be customized using either the endIcon
prop or the ExpandableBlock.EndIcon
subcomponent.
import * as React from 'react';
import { ExpandableBlock } from '@itwin/itwinui-react';
import { SvgSmileyHappy } from '@itwin/itwinui-icons-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper status='positive'>
<ExpandableBlock.Trigger>
<ExpandableBlock.ExpandIcon />
<ExpandableBlock.LabelArea>
<ExpandableBlock.Title>Positive block</ExpandableBlock.Title>
</ExpandableBlock.LabelArea>
<ExpandableBlock.EndIcon />
</ExpandableBlock.Trigger>
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper status='negative'>
<ExpandableBlock.Trigger>
<ExpandableBlock.ExpandIcon />
<ExpandableBlock.LabelArea>
<ExpandableBlock.Title>Negative block</ExpandableBlock.Title>
</ExpandableBlock.LabelArea>
<ExpandableBlock.EndIcon />
</ExpandableBlock.Trigger>
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper status='warning'>
<ExpandableBlock.Trigger>
<ExpandableBlock.ExpandIcon />
<ExpandableBlock.LabelArea>
<ExpandableBlock.Title>Warning block</ExpandableBlock.Title>
</ExpandableBlock.LabelArea>
<ExpandableBlock.EndIcon />
</ExpandableBlock.Trigger>
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper status='informational'>
<ExpandableBlock.Trigger>
<ExpandableBlock.ExpandIcon />
<ExpandableBlock.LabelArea>
<ExpandableBlock.Title>Informational block</ExpandableBlock.Title>
</ExpandableBlock.LabelArea>
<ExpandableBlock.EndIcon />
</ExpandableBlock.Trigger>
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger>
<ExpandableBlock.ExpandIcon />
<ExpandableBlock.LabelArea>
<ExpandableBlock.Title>Happy block</ExpandableBlock.Title>
</ExpandableBlock.LabelArea>
<ExpandableBlock.EndIcon>
<SvgSmileyHappy />
</ExpandableBlock.EndIcon>
</ExpandableBlock.Trigger>
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
Small
A small expandable block is achieved by using the size
prop.
import * as React from 'react';
import { ExpandableBlock } from '@itwin/itwinui-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper size='small'>
<ExpandableBlock.Trigger label='Small expandable Block' />
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
Borderless
The borderless expandable block is useful in tighter areas where using a default expandable block would visibly cause too many blocks. The borderless expandable block is achieved by using the styleType
prop.
import * as React from 'react';
import { ExpandableBlock } from '@itwin/itwinui-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper styleType='borderless'>
<ExpandableBlock.Trigger label='Borderless expandable block' />
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
Disabled
An expandable block can be disabled by using the disabled
prop.
import * as React from 'react';
import { ExpandableBlock } from '@itwin/itwinui-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper disabled>
<ExpandableBlock.Trigger label='Disabled expandable block' />
<ExpandableBlock.Content>Content in block!</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
Secondary actions
Expandable blocks can have secondary actions, such as buttons. The following example uses endIcon
prop to display an icon button on the right side of the trigger.
import * as React from 'react';
import { ExpandableBlock, IconButton } from '@itwin/itwinui-react';
import { SvgMoreVertical } from '@itwin/itwinui-icons-react';
export default () => {
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger
label='My disclosure'
endIcon={
<IconButton
label='More options'
styleType='borderless'
size='small'
onClick={() => console.log('Clicked more options')}
>
<SvgMoreVertical />
</IconButton>
}
/>
<ExpandableBlock.Content>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Culpa
doloremque sint nobis harum. Harum atque, minima in aliquid nostrum
corporis.
</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
This functionality is made possible via the LinkAction
component, which is used internally by the main trigger.
Guidelines
Expandable blocks are used to progressively disclose information. Read this article to learn more about progressive disclosure. Expandable blocks should not be used with flattened hierarchy or information panels. Table rows can also expand similarly to expandable block.
Forms
Expandable blocks are used in pages to divide up content in sections, in forms for example. If each section has many fields, using expandable blocks will help alleviate the UI and prevent the user from scrolling endlessly to get to the section they are looking for.
import * as React from 'react';
import {
ExpandableBlock,
Label,
Input,
InputGroup,
Radio,
InputGrid,
} from '@itwin/itwinui-react';
export default () => {
const nameSection = (
<>
<InputGrid>
<Label htmlFor='name' required>
Name
</Label>
<Input id='name' key='name' placeholder='Enter name' />
</InputGrid>
<InputGrid>
<Label htmlFor='occupation'>Occupation</Label>
<Input
id='occupation'
key='occupation'
placeholder='Enter occupation'
/>
</InputGrid>
</>
);
const colorSection = (
<InputGroup key='color' label='Choose your favorite color' required>
<Radio name='color' value='Red' label='Red' />
<Radio name='color' value='Orange' label='Orange' />
<Radio name='color' value='Yellow' label='Yellow' />
<Radio name='color' value='Green' label='Green' />
<Radio name='color' value='Blue' label='Blue' />
<Radio name='color' value='Purple' label='Purple' />
</InputGroup>
);
const reasonSection = (
<>
<Label htmlFor='explanation' required>
Why is this your favorite color
</Label>
<Input
id='explanation'
key='explanation'
placeholder='Enter text here...'
/>
</>
);
return (
<div className='demo-container'>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger label='Name' />
<ExpandableBlock.Content>{nameSection}</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger label='Favorite Color' />
<ExpandableBlock.Content>{colorSection}</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
<ExpandableBlock.Wrapper>
<ExpandableBlock.Trigger label='Reasoning' />
<ExpandableBlock.Content>{reasonSection}</ExpandableBlock.Content>
</ExpandableBlock.Wrapper>
</div>
);
};
Expandable blocks vs hierarchy tree
While these two patterns may appear similar, they both fulfill a different role and are not interchangeable. Here are some tips to determine if an expandable block is what you need.
Use an expandable block when:
- You have a page with different sections all containing user-generated content that would benefit from being split up
- There is only one level of indentation possible at all times
- The content you want to be expandable varies from simple list items to more complex form components (such as text fields, buttons, etc.)
Use a hierarchy tree when:
- You require a pattern that works with several levels of data (folder drilling)
- There are only list items in the pattern
- The hierarchy is not necessarily linear and may branch out
Props
Prop | Description | Default |
---|---|---|
status | Status of the block.
When set, a colored status icon is shown at the end of the main text. "positive" | "negative" | "warning" | "informational" | |
isExpanded | Whether or not to show the block's content. boolean | false |
onToggle | Callback function for toggling an expansion state. (isExpanding: boolean) => void | |
children | Content in the expandable block. ReactNode | |
size | Modify size of the ExpandableBlock. "small" | "default" | 'default' |
styleType | Style of the ExpandableBlock.
Use 'borderless' to hide outline. "default" | "borderless" | 'default' |
disabled | Disables ExpandableBlock. boolean | false |
title | ReactNode | |
caption | ReactNode | |
endIcon | ReactNode | |
as | "symbol" | "object" | "div" | "caption" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | ... 159 more ... | FunctionComponent<...> |