GrAvatar

  • core
  • data
  • API · 8 props

Displays a user photo, or initials / a fallback when it is missing.

import { GrAvatar } from '@feugene/granularity/components/GrAvatar'

Overview

When to take it

  • a person or an entity is recognised by a picture — a list of participants, the author of a comment, the owner of a task;
  • there may be no picture — the fallback runs down a chain: src, fallbackSrc, initials from name, the slot;
  • a presence status is needed — a dot on the avatar instead of a separate marker beside it;
  • there are several participants — GrAvatarGroup collects them into a row with overlap and a counter.

When to take something else

NeedTake
The image has to be examinedGrImageViewer
An icon is shown, not a personGrIcon
A counter on top of a control is neededGrBadgeWrap
A status as textGrBadge

Variants every tone and view, rendered by the real component

Variants · GrAvatar
status \ shapecirclesquare
online
offline
busy
away

Playground controls come from the API, not from hand

Stage

Loading…

0 changed· state is in the URL

Examples 4 each with a live demo and its code

  • A face for every event

    A photo when there is one; without it name gives the initials and the accessible name, and auto-color a colour of its own — the same person keeps it across the product, so the feed is read by spots before words. A robot is not a person: the default slot takes its icon.

    Activity
    Ada Lin sent invoice INV-0418 to Northwind Traders9:41
    GW
    Grace Wu changed the due date of INV-0417 to 12 October9:12
    Billing robot charged Contoso Ltd €432.00 by card8:30
    Linus Ray added a note to Tailspin ToysYesterday
    MO
    Mina Ortiz invited [email protected] as an editorYesterday
  • Presence on the face

    status puts the marker on the avatar, because presence belongs to the person, not to the row: in a list of twenty the eye finds who is online without reading. The dot is decorative — the status is announced in words from the locale, since colour alone carries no meaning.

    Members1 online · 4 in the workspace
    ALonline
    Ada LinOnline
    Owner
    GWbusy
    Grace WuIn a meeting until 11:00
    Admin
    LRaway
    Linus RayAway for 20 minutes
    Editor
    MOoffline
    Mina OrtizLast seen 2 days ago
    Viewer
  • A team in one short row

    GrAvatarGroup overlaps the faces; max keeps the row short and folds the rest into «+N», total counts the people the list did not bring. The group is named, so a screen reader hears «Invoice editor team, and 3 more» instead of six nameless pictures; size reaches every avatar inside.

    Projects
    Invoice editorShips 20 Oct
    ALGWLR
    VAT reports for GermanyShips 4 Nov
    GWOH
    Mobile appShips in Q1
    SKLRAL
  • Companies square, people round

    shape tells a workspace from a person at a glance. A logo whose link no longer answers falls back along the chain — src, then fallback-src, then initials from name — without a broken-image icon; alt names the picture. :size="40" is the escape hatch for a diameter off the scale.

    Switch account

API generated from the package · cannot drift

Props

PropTypedefaultDescription
sizeGrSizeWithPx | undefinedundefinedThe size by the canonical scale (`xs|sm|md|lg`) — then `GrConfigProvider` applies. A number is an escape hatch: an avatar is needed at an arbitrary diameter (24px in a list row, 96px in a profile), and four steps of the scale do not cover that.
namestring | undefinedundefinedThe name of the participant: it gives the initials and the accessible name of the avatar.
srcstring | undefinedundefinedThe address of the photo. While it loads — a skeleton; if it fails to load — `fallbackSrc`, then the initials.
fallbackSrcstring | undefinedundefinedA fallback picture: shown when `src` did not load.
altstring | undefinedundefinedThe accessible name of the avatar; stronger than `name` when the label for a screen reader must be different.
shapeGrAvatarShape | undefinedundefinedA circle or a square with rounded corners. `circle` by default; a group sets the shape for the whole row.
autoColorboolean | undefinedundefinedColour the background by the name: the same name always gives the same colour. Off by default — a grey avatar is a deliberate neutral default, while a coloured one can clash with the styling of the product. The palette is set by the theme (`--gr-avatar-N-bg`/`-fg`), the component only picks the slot.
status"online" | "offline" | "busy" | "away" | undefinedundefinedThe status of the participant. The dot is decorative — a hidden label goes beside it.

Slots

SlotTypeDescription
defaultanyContent instead of the picture and the initials.

Types

Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.

Import
import type { GrAvatarGroupProps, GrAvatarProps, GrAvatarShape } from '@feugene/granularity/components/GrAvatar'

Filedist/types/components/GrAvatar/GrAvatarGroup.vue.d.ts

GrAvatarGroupPropsinterface
interface GrAvatarGroupProps {
    size?: GrSizeWithPx;
    shape?: GrAvatarShape;
    max?: number;
    total?: number;
    ariaLabel?: string;
}

Filedist/types/components/GrAvatar/config.d.ts

grAvatarConfigconst
const grAvatarConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrAvatar">;

Filedist/types/components/GrAvatar/GrAvatar.vue.d.ts

GrAvatarPropsinterface
interface GrAvatarProps {
    size?: GrSizeWithPx;
    src?: string;
    fallbackSrc?: string;
    alt?: string;
    name?: string;
    shape?: GrAvatarShape;
    autoColor?: boolean;
    status?: GrAvatarStatus;
}

Filedist/types/components/GrAvatar/grAvatarStyles.d.ts

GrAvatarShapetype
type GrAvatarShape = 'circle' | 'square';
GrAvatarStatustype
type GrAvatarStatus = typeof GR_AVATAR_STATUSES[number];
initialsFromfunction
function initialsFrom(name: string): string;

Filedist/types/components/GrAvatar/safelist.d.ts

grAvatarSafelistconst
const grAvatarSafelist: string[];

Filedist/types/components/GrAvatar/defaults.d.ts

GrAvatarConfigurablePropsinterface
interface GrAvatarConfigurableProps {
    size: GrComponentSize;
    shape: GrAvatarShape;
    autoColor: boolean;
}

Usage from the library prose

What gets shown

The fallback order: src → fallbackSrc → initials from name → the default slot.

vue
<GrAvatar src="https://cdn.example/u/42.png" fallback-src="/avatar.svg" name="Ada Lovelace" />

A broken link is handled: on @error the component moves to the next option, and the browser does not draw the broken-image icon. Changing src resets the error — a new link does not inherit the fate of the previous one.

While the picture is on its way, its place is held by a skeleton: otherwise a row of avatars flickers with empty circles.

The name and the initials

name provides the initials (the first letters of the first two words) and the accessible name. When there is a picture, the name serves as its alt; without a picture the avatar itself takes the img role and the name — otherwise a circle with initials is empty for a screen reader. alt beats name, the slot beats the initials.

The initials function is available separately: import { initialsFrom } from '@feugene/granularity'.

The type size is computed from the diameter — a third of it, but no less than 10px. The size of an avatar can be an arbitrary number of pixels, so a map across the steps of the scale does not cover it. The rule is one for the initials, the slot text and the “+N” counter of GrAvatarGroup: they stand in the same row, and different proportions would read as a defect.

Auto colour by name

autoColor colours the background by the name: the same name always gives the same colour, so a person in a list can be recognised by the patch before the initials are read.

It is off by default and is switched on for the whole application through GrConfigProvider:

vue
<GrConfigProvider :component-defaults="{ GrAvatar: { autoColor: true } }">

A grey avatar is a deliberate neutral default: a coloured circle argues with the design where an avatar stands inside a dense interface. Switching it on therefore remains a decision of the application rather than of the library.

There is no palette inside the component. The six slots (--gr-avatar-1-bg/-fg … -6-) are declared in the theme of the component itself (components/GrAvatar/themes/), and each by default refers to the -light/-text pair of a ready tone — the same one the soft variant of GrBadge stands on. The component computes only the number of the slot.

The palette deliberately does not go into the global theme: one component needs it, and there it would be paid for by whoever does not take GrAvatar as well. The palette has no dark file — a slot refers to a role, and the role switches together with the theme on its own.

An application that has no need of a pale red or a pale green avatar only has to override the slot:

css
:root { --gr-avatar-4-bg: var(--gr-slate-light); --gr-avatar-4-fg: var(--gr-slate-text); }

Three of the six tones are semantic, and that is a choice rather than an oversight: the tones are pale, and in a row of people colour reads as identity rather than as a state. The override above exists precisely for those who disagree.

The colour is visible only under the initials: a picture covers the background entirely, and an empty avatar has nothing to colour. The “+N” counter of GrAvatarGroup stays neutral as well — it is not a participant, it has no name.

The contrast of a pair and the distinguishability of the slots are held by the src/__tests__/avatarPalette.test.ts gate — in both themes at once.

The status
vue
<GrAvatar name="Ada Lovelace" status="online" />

online | offline | busy | away. The dot is decorative (aria-hidden), and the status is announced with a word from the locale (gr.avatar.status.*): colour on its own carries no meaning.

A row of participants
vue
<GrAvatarGroup :max="3" :total="9" aria-label="Release team">
  <GrAvatar v-for="member in team" :key="member.id" :name="member.name" />
</GrAvatarGroup>

max limits the number of visible avatars, the remainder collapses into “+N”; total is needed when the slot holds only part of the participants. The group is declared role="group", and its name contains both the label and the number hidden — a screen reader says “Release team, and 6 more” rather than a set of nameless pictures.

The size and shape of the group reach the children through context, so the row does not fall apart.

Size and shape

size accepts a step of the scale (xs…lg, read from GrConfigProvider) or a number of pixels — an avatar has historically had an arbitrary diameter. shape (circle | square) is likewise configured globally through componentDefaults.GrAvatar.shape.