Gecko UIGecko UI

Avatar

A picture of someone, falling back to their initials

Avatar

A picture of someone, falling back to their initials.

Installation

import { Avatar, AvatarGroup } from '@geckoui/geckoui';

Basic Usage

<Avatar name="Ada Lovelace" src={user.image} />
<Avatar name="Grace Hopper" color="primary" />
<Avatar name="Cher" color="success" />
<Avatar />

Props API

Avatar

PropTypeDefaultDescription
srcstring-Image to show. The fallback takes over when it is missing or fails
altstring-Alternative text for the image. Falls back to name
namestring-Whose avatar this is. Its initials are drawn when there is no image
fallbackReactNode | FC-What to draw instead of the initials
sizekeyof AvatarSizeMap'md'xs, sm, md, lg or xl. Taken from the group when unset
shapekeyof AvatarShapeMap'circle'circle, rounded or square. Taken from the group when unset
colorkeyof AvatarColorMap'default'Accent behind the fallback
onClickMouseEventHandler-Makes it a button, reachable and usable by keyboard
classNamestring-CSS class for the avatar
...restHTMLAttributes<HTMLSpanElement>-All standard span attributes

AvatarGroup

PropTypeDefaultDescription
maxnumber-How many to show before the rest are counted
sizekeyof AvatarSizeMap'md'Size for every avatar in the group
shapekeyof AvatarShapeMap'circle'Corner treatment for every avatar in the group
interactivebooleantrueLift and name each avatar on hover, and open the overflow from the count
renderOverflow({ avatars }) => ReactNodethe list of namesWhat fills the overflow overlay
classNamestring-CSS class for the group
...restHTMLAttributes<HTMLDivElement>-All standard div attributes

Examples

Sizes

<Avatar name="Ada Lovelace" size="xs" />
<Avatar name="Ada Lovelace" size="xl" />

Shapes

<Avatar name="Ada Lovelace" shape="circle" />
<Avatar name="Ada Lovelace" shape="rounded" />
<Avatar name="Ada Lovelace" shape="square" />

Colours

<Avatar name="Ada Lovelace" color="primary" />
<Avatar name="Ada Lovelace" color="success" />

The colour is the accent behind the fallback, drawn from the same semantic tokens as Badge and Alert. An avatar showing a photo does not use it.

What it falls back to

Ada Lovelace

In order: the image, then fallback, then the initials from name, then a person icon.

<Avatar name="Ada Lovelace" src={user.image} />  {/* photo */}
<Avatar name="Ada Lovelace" />                    {/* AL */}
<Avatar name="Cher" />                            {/* C */}
<Avatar />                                        {/* person icon */}
<Avatar fallback="AI" color="primary" />          {/* AI */}

An image that fails to load falls through to the same chain, and a new src is given a fresh attempt, so one dead URL does not hide every image after it in a list.

Initials are the first letter of the first and last word, uppercased.

Groups

<AvatarGroup max={3}>
  <Avatar name="Ada Lovelace" />
  <Avatar name="Grace Hopper" />
  <Avatar name="Alan Turing" />
  <Avatar name="Katherine Johnson" />
  <Avatar name="Margaret Hamilton" />
</AvatarGroup>

Avatars overlap, each sitting over the one after it. size and shape on the group apply to everything inside, and an avatar can still set its own.

Hover one for its name, or the count for everyone who did not fit.

What is behind the count

<AvatarGroup
  max={3}
  renderOverflow={({ avatars }) => (
    <div>
      <p>{avatars.length} more on this project</p>
      <ul>
        {avatars.map((avatar) => (
          <li key={avatar.name}>{avatar.name}</li>
        ))}
      </ul>
    </div>
  )}>
  <Avatar name="Ada Lovelace" />
  <Avatar name="Grace Hopper" />
  <Avatar name="Alan Turing" />
  <Avatar name="Katherine Johnson" />
  <Avatar name="Margaret Hamilton" />
</AvatarGroup>

avatars holds the props of everyone past max — name, src, and anything else you put on them — so the overlay can show whatever you like, not only avatars.

The overlay opens on hover and is placed for you. renderOverflow fills it.

Static

<AvatarGroup max={3} interactive={false}>
  <Avatar name="Ada Lovelace" />
  <Avatar name="Grace Hopper" />
  <Avatar name="Alan Turing" />
  <Avatar name="Katherine Johnson" />
</AvatarGroup>

interactive={false} drops the lift, the names and the overflow overlay. The count stays.

Clickable

Click or tab to one

<Avatar name="Ada Lovelace" onClick={() => open(user)} />

An onClick turns the avatar into a button: it joins the tab order, answers Enter and Space, takes a focus ring and shows a pointer. Without one it stays a plain image.

Styling with CSS

VariableDefaultApplies to
--gecko-avatar-accentper colorFallback text and tint
--gecko-avatar-bg-base--color-surface-hover-strongWhat the accent is tinted into
--gecko-avatar-bg-mix14%How much accent goes into the tint
--gecko-avatar-sizeper sizeWidth and height
--gecko-avatar-radiusper shapeCorner radius
--gecko-avatar-font-sizeper sizeInitials
--gecko-avatar-group-overlapper sizeHow far each avatar tucks under the last
--gecko-avatar-group-ring--color-surface-primaryThe ring separating overlapping avatars
--gecko-avatar-group-ring-width2pxRing thickness
--gecko-avatar-group-lift0.375remHow far an avatar rises on hover

The fallback is opaque, because avatars overlap. Set --gecko-avatar-bg-base to whatever they sit on if that is not the page background:

.GeckoUIAvatarGroup {
  --gecko-avatar-bg-base: var(--color-surface-secondary);
  --gecko-avatar-group-ring: var(--color-surface-secondary);
}

Class names and data attributes

  • GeckoUIAvatar - The avatar, with data-size, data-shape, data-color and data-clickable
  • GeckoUIAvatar__image - The image
  • GeckoUIAvatar__fallback - What shows in its place
  • GeckoUIAvatarGroup - The group, with data-size and data-interactive
  • GeckoUIAvatarGroup__slot - Holds one avatar's place in the row. It stays put while the avatar inside it lifts, so the hover target does not move
  • GeckoUIAvatarGroup__overflow - The count
  • GeckoUIAvatarGroup__list - The default overflow list

Adding your own sizes

Every axis is an extensible map, so you can add keys through module augmentation and style them with CSS. No component change is needed:

declare module '@geckoui/geckoui' {
  interface AvatarSizeMap {
    '2xl': unknown;
  }
}

<Avatar name="Ada Lovelace" size="2xl" />
.GeckoUIAvatar[data-size="2xl"] {
  --gecko-avatar-size: 6rem;
  --gecko-avatar-font-size: 1.75rem;
}

The same works for AvatarShapeMap and AvatarColorMap.

Accessibility

An avatar showing a photo is labelled by the image's alt, which falls back to name. When the fallback is on screen the avatar itself takes role="img" and that label, and the initials are hidden so they are not read out letter by letter.

With onClick it becomes role="button" and enters the tab order, keeping the same label.

The count is labelled "2 more".

  • Skeleton - shape="circle" holds an avatar's place while it loads
  • Badge - Small inline labels, sharing the same colour tokens
  • Tooltip - What the group uses to name an avatar on hover