GUILD OF GLEKS UIv21.19.0

gog-avatar

Avatar 21.17.0

A person or an organisation as a picture — with a fallback, which is the point. A picture of a person is the image on a page most likely to be missing, and a bare <img> shows the browser's broken-image glyph every time it is. gog-avatar falls back to the initials, then to an icon, and names itself once for a screen reader. gog-avatar-group stacks several, with a +N for the rest.

Overview

Import the component and give it a name; a src is optional.

typescript
import { AvatarComponent, AvatarGroupComponent } from '@guildofgleks/ui';

@Component({
  // ...
  imports: [AvatarComponent, AvatarGroupComponent],
})

Basic usage — a picture, the initials when there is none, and the icon when there is no name either:

<gog-avatar name="Ada Lovelace" [src]="photo" />
<gog-avatar name="Grace Hopper" />
<gog-avatar />

Examples

The fallback chain

Picture → initials → icon. The third src is an image that cannot load — bytes no browser can decode, standing in for a URL that 404s — and this page is server-rendered, so that picture fails before the app hydrates — its error event fires before any listener exists. The avatar reads the image's own state on its first render in the browser instead, which is why it shows initials and not a broken image. While a slow picture loads, the initials show under it, so nothing moves when it arrives.

picture
no src
src fails
no name either
<div>
  <gog-avatar name="Ada Lovelace" [src]="photo" size="lg" />
  <span>picture</span>
</div>
<div>
  <gog-avatar name="Ada Lovelace" size="lg" />
  <span>no src</span>
</div>
<div>
  <!-- An image that cannot load. On this server-rendered page it fails before the app hydrates. -->
  <gog-avatar name="Ada Lovelace" [src]="broken" size="lg" />
  <span>src fails</span>
</div>
<div>
  <gog-avatar size="lg" />
  <span>no name either</span>
</div>

Sizes, and the skeleton that stands in for them

Five sizes, 24 to 96px — the skeleton circle's sizes by reference, so a gog-skeleton with shape="circle" at the same size is the avatar's loading placeholder and swaps for it without moving anything. --gog-avatar-size overrides the diameter on one instance.

gog-avatar
gog-skeleton
<div>
  <span>gog-avatar</span>
  @for (size of sizes; track size) {
    <gog-avatar name="Grace Hopper" [size]="size" />
  }
</div>
<div>
  <span>gog-skeleton</span>
  @for (size of sizes; track size) {
    <gog-skeleton shape="circle" [size]="size" />
  }
</div>

Shape

circle for a person, rounded for an organisation or a product. The picture takes the avatar's own corner, so the two can never disagree.

<gog-avatar name="Ada Lovelace" [src]="photo" size="lg" />
<gog-avatar name="Ada Lovelace" size="lg" />
<gog-avatar name="Acme Incorporated" initials="AC" shape="rounded" size="lg" />
<gog-avatar name="Acme Incorporated" [src]="logo" shape="rounded" size="lg" />

Initials

The first letter of the first and the last word of name, upper-cased — per grapheme, so a name that starts with an emoji or an accented letter is not cut in half. initials overrides them, for an organisation's own short form. gogAvatarInitials(name) is exported if you need the same rule elsewhere.

Ada King Lovelace
grace hopper
Plato
Émilie du Châtelet
🦊 Fox
initials="AC"
@for (person of names; track person) {
  <div>
    <gog-avatar [name]="person" />
    <span>{{ person }}</span>
  </div>
}
<div>
  <gog-avatar name="Acme Incorporated" initials="AC" shape="rounded" />
  <span>initials="AC"</span>
</div>

With a badge

Status is gogBadge on the avatar — there is no status input. On a circle the badge anchors where the circle crosses its box's diagonal rather than in the empty corner, so a count sits on the edge and a dot is centred on the circle; on a rounded avatar it keeps the box corner.

<gog-avatar name="Ada Lovelace" [src]="photo" gogBadge="3" badgeAriaLabel="3 unread" />
<gog-avatar name="Grace Hopper" size="lg" gogBadge badgeDot badgeVariant="success" />
<gog-avatar name="Acme Incorporated" shape="rounded" size="lg" gogBadge="12" />

Decorative, and inside a button

Beside a name that is already written out, set decorative, or a screen reader hears the name twice. An avatar that opens something is not itself a button: put it in a gog-button, name the button, and make the avatar decorative.

Ada Lovelace
<!-- The name is written beside it, so the avatar would only say it twice. -->
<span><gog-avatar name="Ada Lovelace" size="sm" decorative /> Ada Lovelace</span>

<!-- A pressable avatar is a button that contains one: the button carries the name. -->
<gog-button variant="ghost" [gogMenuTrigger]="account" ariaLabel="Account menu for Ada Lovelace">
  <gog-avatar name="Ada Lovelace" size="xsm" decorative />
  <gog-icon name="chevron-down" />
</gog-button>
<gog-menu #account ariaLabel="Account">
  <button gogMenuItem type="button">Profile</button>
  <button gogMenuItem type="button">Sign out</button>
</gog-menu>

Groups

gog-avatar-group overlaps the avatars written inside it by an eighth of their diameter, rings each one in the page colour, and turns the ones past max into a +N.

max

max counts the +N avatar, so the row's width is known from max alone: seven people at max="5" draw four and +3. The ones not drawn leave the accessibility tree, and the +N is named for them — "3 more", from GOG_CONFIG.labels.moreAvatars.

max=unset
max=5
max=3
@for (max of maxes; track $index) {
  <div>
    <span>max={{ max ?? 'unset' }}</span>
    <gog-avatar-group [max]="max" ariaLabel="Team">
      @for (person of team; track person.name) {
        <gog-avatar [name]="person.name" [src]="person.src" />
      }
    </gog-avatar-group>
  </div>
}

One size for the row, and a long tail

The group's size reaches every avatar through --gog-avatar-size, so the row is one size whatever each avatar's own size says. Past 99 the +N draws 99+, the way gogBadge caps a count; its name keeps the exact number.

xsm
sm
md
lg
slg
@for (size of sizes; track size) {
  <div>
    <span>{{ size }}</span>
    <gog-avatar-group [size]="size" [max]="4" ariaLabel="Members">
      @for (person of members; track person) {
        <gog-avatar [name]="person" />
      }
    </gog-avatar-group>
  </div>
}

On a card

The ring is the page colour (--gog-avatar-group-ring-color), which is right on the page and visibly wrong on anything raised above it. Set it to the surface the group sits on.

Default ring

Ring set to the card

<gog-card>
  <h3 gogCardHeader>Default ring</h3>
  <gog-avatar-group ariaLabel="Shared with">
    @for (person of people; track person) {
      <gog-avatar [name]="person" />
    }
  </gog-avatar-group>
</gog-card>
<gog-card>
  <h3 gogCardHeader>Ring set to the card</h3>
  <gog-avatar-group
    ariaLabel="Shared with"
    style="--gog-avatar-group-ring-color: var(--gog-surface-color)"
  >
    @for (person of people; track person) {
      <gog-avatar [name]="person" />
    }
  </gog-avatar-group>
</gog-card>

Accessibility

An avatar is an image of someone, and a screen reader should hear who — once.

  • Named — with a name it is role="img" named by it. The picture inside is alt="" and the initials are aria-hidden, so it is "Ada Lovelace, image", not "Ada Lovelace, A L".
  • Decorative — decorative sets aria-hidden="true", for an avatar beside a name already written out. An avatar with no name is decorative on its own: there is nothing true to say.
  • Badges — an image's children are not read, so a gogBadge on a named avatar becomes its description (aria-describedby): "Ada Lovelace, image, 3 unread".
  • Pressable — never on the avatar. A button that contains a decorative avatar carries the name and the keyboard behaviour.
  • Groups — role="group", named by ariaLabel ("Assignees", "Shared with"). The avatars past max are display: none; the +N says how many.

API Reference

gog-avatar inputs

NameTypeDefaultDescription
srcstring | nullnullThe picture. Falls back to the initials when unset, when it fails, and when it failed before hydration.
namestring''Whose avatar: its accessible name, and the source of the initials.
initialsstring | undefinedfrom nameOverrides the derived initials — an organisation's own short form.
iconNameGogIconName'user'The last fallback, when there is neither a picture nor any initials.
sizeGogSize'md''xsm' | 'sm' | 'md' | 'lg' | 'slg' — 24, 32, 48, 64 and 96px, the skeleton circle's sizes.
shapeGogAvatarShape'circle''circle' for a person, 'rounded' for an organisation or a product.
decorativebooleanfalseHides it from assistive tech, beside a name already written out. An avatar with no name is decorative whatever this says.

gog-avatar-group inputs

NameTypeDefaultDescription
maxnumber | nullnullThe most avatars drawn, the +N one included. Unset, every avatar is drawn. The +N is named by GOG_CONFIG.labels.moreAvatars, "N more" by default.
sizeGogSize'md'One size for the whole row; it wins over each avatar's own size.
ariaLabelstring | undefinedundefinedNames the group — "Assignees", "Shared with".

Global Configuration

Set any of these once with provideGogConfig() instead of repeating them on every instance — an instance's own input still wins when it sets one itself. See Global Configuration for the full reference.

  • GOG_CONFIG.labels.moreAvatars — gog-avatar-group's +N avatar

Styling Tokens

Every CSS custom property the avatar and the group paint with. Override any of them — on a single instance, a subtree, or a theme — to restyle it. See the Theming guide for the full token-layering model, or the Theme Generator to tweak these live.

TokenDescription
--gog-avatar-xsm-size / -sm-size / -md-size / -lg-size / -slg-sizeThe diameter at each size: the skeleton circle’s sizes by reference (24/32/48/64/96px), so a circle skeleton swaps for an avatar without moving anything.
--gog-avatar-sizeUndeclared instance override of the diameter. gog-avatar-group sets it on itself, which is how one size reaches the whole row.
--gog-avatar-bg / -colorThe fill behind the initials or the icon, and their colour. The fill is the skeleton’s step made opaque, so it stands off any ground and matches its own placeholder.
--gog-avatar-font-family / -font-weight / -line-heightHow the initials are set.
--gog-avatar-initials-ratio / -icon-ratioThe initials and the icon, as a fraction of the diameter, so they scale with whichever size resolves.
--gog-avatar-rounded-radiusThe corner of shape="rounded". A circle needs none.
--gog-avatar-badge-inset-ratioWhere a circle crosses its box’s diagonal, as a fraction of the diameter: where a gogBadge on a round avatar anchors.
--gog-avatar-group-overlap-ratioHow far each avatar in a group steps back over the one before, of the diameter — an eighth, which leaves a typical pair of initials uncovered.
--gog-avatar-group-ring-width / -ring-colorThe ring between overlapping avatars. The colour is the page’s; set it to the surface the group sits on, a card or a panel.
--gog-avatar-group-more-initials-ratioThe +N avatar’s text, smaller because it can be three characters (99+).