Components
Avatar stack
Avatar stack stacks a collection of avatar elements
Avatar stack is under development. If you have feedback or suggestions, please report them on Github or in Slack.
HTML
Unable to parse html
const Preview = () => ( <EXPERIMENTAL_AvatarStack> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <BriefcaseIcon /> </Avatar> <Avatar aria-label='' initials='sm' /> <Avatar aria-label=''>md</Avatar> <Avatar aria-label='' initials='on' /> </EXPERIMENTAL_AvatarStack> ); render(<Preview />)
Use avatar stack when
- A group of people or entities should be displayed together, but space is limited.
- You need to signal that multiple people are involved, without showing everyone at full size.
Avoid avatar stack when
- There is only ever a single avatar to display.
- Each person or entity must be clearly identifiable by name or role at the same time.
Examples
Customization
Avatar stack is designed to be flexible enough to cover many different needs and use cases.
HTML
Unable to parse html
const Playground = () => { const [expandable, setExpandable] = useState<undefined | true>(undefined); const [square, setSquare] = useState(false); const [size, setSize] = useState(64); const [overlap, setOverlap] = useState(50); const [gap, setGap] = useState(2); const labelStyle = { display: 'flex', flexDirection: 'column', gap: 'var(--ds-size-2)', accentColor: 'var(--ds-color-base-default)', } as const; return ( <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--ds-size-8)', minHeight: '370px', }} > <fieldset style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 320px), 1fr))', gap: 'var(--ds-size-4)', }} > <div style={{ display: 'flex', gap: 'var(--ds-size-3)', alignItems: 'center', }} > <Checkbox label='Expandable' checked={expandable !== undefined} onChange={() => setExpandable((prev) => (prev ? undefined : true))} /> <Checkbox label='square' checked={square} onChange={() => setSquare((prev) => !prev)} /> </div> <Label style={labelStyle}> avatarSize {`${size}px`} <input min='24' max='150' step='0.1' type='range' value={size} onChange={(e) => setSize(Number((e.target as HTMLInputElement).value)) } /> </Label> <Label style={labelStyle}> Overlap {`${overlap}`} <input min='-10' max='100' step='1' type='range' value={overlap} onChange={(e) => setOverlap(Number((e.target as HTMLInputElement).value)) } /> </Label> <Label style={labelStyle}> Gap {`${gap}px`} <input min='0' max='15' step='1' type='range' value={gap} onChange={(e) => setGap(Number((e.target as HTMLInputElement).value)) } /> </Label> </fieldset> <EXPERIMENTAL_AvatarStack overlap={overlap} data-suffix={`+10`} gap={`${gap}px`} avatarSize={`${size}px`} expandable={expandable} > <Avatar aria-label='' variant={square ? 'square' : 'circle'}> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label='' variant={square ? 'square' : 'circle'}> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label='' variant={square ? 'square' : 'circle'}> md </Avatar> <Avatar aria-label='' variant={square ? 'square' : 'circle'}> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label='' variant={square ? 'square' : 'circle'}> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> </EXPERIMENTAL_AvatarStack> </div> ); }; render(<Playground />)
Sizes
The size of avatars in an avatar stack is controlled via avatarSize and can be specified in any valid CSS size unit for maximum flexibility.
HTML
Unable to parse html
const DataSize = () => ( <div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--ds-size-8)' }}> <fieldset> <legend>avatarSize='var(--ds-size-8)'</legend> <EXPERIMENTAL_AvatarStack avatarSize={'var(--ds-size-8)'}> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> </EXPERIMENTAL_AvatarStack> </fieldset> <fieldset> <legend>avatarSize='3em'</legend> <EXPERIMENTAL_AvatarStack avatarSize='3em'> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> </EXPERIMENTAL_AvatarStack> </fieldset> <fieldset> <legend>avatarSize='clamp(2rem, 1.5rem + 2vw, 4rem)'</legend> <EXPERIMENTAL_AvatarStack avatarSize='clamp(2rem, 1.5rem + 2vw, 4rem)'> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> </EXPERIMENTAL_AvatarStack> </fieldset> </div> ); render(<DataSize />)
Gap
The visible space between avatars can be customized with gap
HTML
Unable to parse html
const Gap = () => ( <div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--ds-size-8)' }}> <fieldset> <legend>gap='2px'</legend> <EXPERIMENTAL_AvatarStack avatarSize='3rem' gap='2px'> <Avatar aria-label='' initials='AA' /> <Avatar aria-label='' initials='BB' /> <Avatar aria-label='' initials='CC' /> <Avatar aria-label='' initials='DD' /> </EXPERIMENTAL_AvatarStack> </fieldset> <fieldset> <legend>gap='4px'</legend> <EXPERIMENTAL_AvatarStack avatarSize='3rem' gap='4px'> <Avatar aria-label='' initials='AA' /> <Avatar aria-label='' initials='BB' /> <Avatar aria-label='' initials='CC' /> <Avatar aria-label='' initials='DD' /> </EXPERIMENTAL_AvatarStack> </fieldset> <fieldset> <legend>gap='6px'</legend> <EXPERIMENTAL_AvatarStack avatarSize='3rem' gap='6px'> <Avatar aria-label='' initials='AA' /> <Avatar aria-label='' initials='BB' /> <Avatar aria-label='' initials='CC' /> <Avatar aria-label='' initials='DD' /> </EXPERIMENTAL_AvatarStack> </fieldset> </div> ); render(<Gap />)
Expandable
In some cases, it may be desirable to expand the stack on hover and focus. This functionality is off by default.
HTML
Unable to parse html
const Expandable = () => ( <div style={{ display: 'flex', flexDirection: 'row', gap: 'var(--ds-size-4)', flexWrap: 'wrap', }} > <fieldset> <legend>expandable</legend> <EXPERIMENTAL_AvatarStack expandable> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> </EXPERIMENTAL_AvatarStack> </fieldset> <fieldset> <legend>expandable="fixed"</legend> <EXPERIMENTAL_AvatarStack expandable='fixed'> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </Avatar> </EXPERIMENTAL_AvatarStack> </fieldset> </div> ); render(<Expandable />)
Variants
Avatar stack supports both round and square variants, but only one variant per stack.
HTML
Unable to parse html
const ShapeVariants = () => ( <EXPERIMENTAL_AvatarStack aria-label='example of square avatars' overlap={40} gap='4px' expandable > <Avatar variant='square' aria-label='variant square' /> <Avatar variant='square' aria-label='Ola Nordmann'> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar variant='square' aria-label='Ola Nordmann'> <img src='/img/component-docs/cats/cat2.webp' alt='' /> </Avatar> <Avatar variant='square' aria-label='Ola Nordmann'> <img src='/img/component-docs/cats/cat3.webp' alt='' /> </Avatar> <Avatar variant='square' aria-label='Ola Nordmann'> <img src='/img/component-docs/cats/cat4.webp' alt='' /> </Avatar> </EXPERIMENTAL_AvatarStack> ); render(<ShapeVariants />)
Indicating avatars not shown
When there are more avatars than can be displayed in the stack, there are two different ways to indicate this.
HTML
Unable to parse html
const AdditionalAvatars = () => ( <> <EXPERIMENTAL_AvatarStack overlap={30}> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <BriefcaseIcon /> </Avatar> <Avatar aria-label='' initials='sm' /> <Avatar data-color='neutral' aria-label='' style={{ '--dsc-avatar-font-size': '1.1rem' } as React.CSSProperties} > +14 </Avatar> </EXPERIMENTAL_AvatarStack> <EXPERIMENTAL_AvatarStack suffix={'+14'}> <Avatar aria-label=''> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </Avatar> <Avatar aria-label=''> <BriefcaseIcon /> </Avatar> <Avatar aria-label='' initials='sm' /> <Avatar aria-label='' initials='on' /> </EXPERIMENTAL_AvatarStack> </> ); render(<AdditionalAvatars />)
Tooltips and links
Avatars in avatar stack can have tooltips and be links, but be aware of accessibility considerations.
HTML
Unable to parse html
const WithTooltipAndLink = () => ( <div style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--ds-size-4)' }}> <fieldset> <legend>Link + Tooltip</legend> <EXPERIMENTAL_AvatarStack overlap={20} aria-label='contributors'> <Tooltip content='Ola Nordmann'> <Avatar aria-label='' asChild> <a href='#'> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </a> </Avatar> </Tooltip> <Tooltip content='Kari Nordmann'> <Avatar aria-label='' asChild> <a href='#'> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </a> </Avatar> </Tooltip> <Tooltip content='Person 2'> <Avatar aria-label='' asChild> <a href='#'> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </a> </Avatar> </Tooltip> <Tooltip content='Person 3'> <Avatar aria-label='' asChild> <a href='#'>BR</a> </Avatar> </Tooltip> </EXPERIMENTAL_AvatarStack> </fieldset> <fieldset> <legend>Link + Tooltip expandable</legend> <EXPERIMENTAL_AvatarStack overlap={50} expandable='fixed' aria-label='contributors' > <Tooltip content='Ola Nordmann'> <Avatar aria-label='' asChild> <a href='#'> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </a> </Avatar> </Tooltip> <Tooltip content='Kari Nordmann'> <Avatar aria-label='' asChild> <a href='#'> <img src='/img/component-docs/cats/cat1.webp' alt='' /> </a> </Avatar> </Tooltip> <Tooltip content='Person 2'> <Avatar aria-label='' asChild> <a href='#'> <img src='/img/component-docs/cats/cat6.webp' alt='' /> </a> </Avatar> </Tooltip> <Tooltip content='Person 3'> <Avatar aria-label='' asChild> <a href='#'>BR</a> </Avatar> </Tooltip> </EXPERIMENTAL_AvatarStack> </fieldset> </div> ); render(<WithTooltipAndLink />)
Guidelines
Avatar stack should be used with caution, as it can be challenging for users to identify individual avatars in a tightly packed stack. Ensure that the use of avatar stack makes sense in the context of the user experience and does not compromise accessibility or usability.
Avatar stack does not support wrapping across multiple lines. If there are more avatars than can fit in the stack, you can use suffix or an additional avatar with +xx to indicate the number of hidden avatars.
Text
aria-label or aria-description can be used on avatar stack to provide context to screen readers about what the stack represents, for example "Meeting participants" or "Team members".