Skip to content

HabAvatar ​

Initials on a tint of a hue derived from the name.

ALGHATKJEDBLTU?
The hue comes from the name — the same person is the same color everywhere
vue
<HabAvatar name="Ada Lovelace" />

The color comes from the name ​

So the same person is the same color on every surface, with nothing stored. No preference to migrate, no column to add, no default to pick for a new user.

The hash is djb2 followed by an avalanche finalizer, and the finalizer is not decoration. The design source records an earlier accumulate-and-modulo version that gave one hue 25% of names and never picked another at all — mixing the high bits down is what makes % 8 see any entropy. habAvatarHue is exported so you can color something else by the same person — a chart series, a cursor — and have it match.

Eight ramp steps, not the full 65: most of the palette's lighten steps are indistinguishable from each other at 24px, and an avatar's whole job is to be told apart at a glance.

No photos ​

Deliberately. These are internal tools, and an avatar that can be a photo needs upload, cropping, a fallback and a broken-image state — four things to build and a fifth to get wrong.

Against HabIconTile ​

A tile says what kind of thing something is; an avatar says who. They share the 14% tint so a tile and an avatar for the same entity read as the same hue.

They differ in one measured way. A tile puts its glyph at the hue's full strength, which clears the 3:1 floor for a non-text object. Initials are text and need 4.5:1 — the source measured full-strength orange at 2.70 and lime at 2.24 on their own tints. So the initials are mixed toward --hab-hue-ink, which inverts per theme; a fixed dark ink measured 1.17 on dark surfaces.

Sizes ​

ALALAL
24 / 32 / 40 — its own ladder, because an avatar is not a control

24 / 32 / 40, its own ladder — an avatar is not a control, so it does not sit on the 34px grid. The initials take the type ladder (11 / 12 / 13) rather than the source's off-ladder 10 / 12 / 14: a fourth and fifth font size existing only inside this component is worse than one pixel.

Accessibility ​

  • role="img" with the full name as the accessible name. The initials are not a name — a screen reader reading "AL" conveys nothing, and the design contract's title is a tooltip that browsers only sometimes also expose as a name.
  • Set decorative when the name is written beside it, which is the common case in a list row or a table cell. Otherwise the name is announced twice.
  • An avatar with no name does not claim to be an image with an empty label.

API ​

Props ​

PropTypeDefaultDescription
colorstringundefinedOverride the derived hue. Any CSS color.
decorativebooleanfalseHides the avatar from assistive tech, for when the name is already written beside it. Two announcements of the same name is noise.
initialsstringundefinedOverride the derived initials.
namestring""Drives both the initials and the color, so the same person is the same color everywhere with nothing stored.
size"md" | "sm" | "lg""md"—

Proprietary — internal use only.