Skip to Content

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 with title, 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<...>