Noctis

Avatar

A user's profile picture, with a graceful fallback. When the image is missing or fails to load, the avatar shows initials or a glyph on a stable, accent-independent swatch — no layout shift, no broken-image icon.

Basic

Compose Avatar.Root (which sets the footprint) with an Avatar.Image and an Avatar.Fallback. Base UI shows the fallback until the image loads, and swaps back to it if the load errors — so the box is always filled. Give the image a meaningful alt, and the fallback a seed (a name, id, or email) to pick a stable colour.

AL

Sizes

size sets the edge length of the box — xs, sm, md (the default), lg, or xl. The initials type scales with it. Avatars use their own footprint scale, not the control-height ladder — an avatar is an image, not a control.

GHGHGHGHGHGH

Shapes

shape is an explicit variant — a round circle (the default) or a rounded-corner box (rounded). The rounded shape reads the radius knob on the capped md step, so it tracks the system radius — softly rounded under the pill default, square when the knob is dialled to 0.

KJKJ

Ring

Set ring for a hairline that follows the shape — it separates an avatar from a same-toned surface. The ring is a box-shadow (not an outline), so it stays round on a circle and rounded on a rounded box.

ALGH

Fallback colours

With no image, the fallback paints initials on a static swatch chosen by hashing the seed — so the same person always gets the same hue. The palette is accent-independent and carries its own light/dark values, so identity stays stable across themes. Omit seed for a neutral muted fill.

ALGHKJRPBL

Avatar item

The most common avatar pattern is an avatar beside a visible name — a roster row or a comment author. Here the avatar is decorative: give Avatar.Image an empty alt and add no role or label, so the name announces once instead of twice. This is the default; see Accessibility for the full contract.

  • AL
    Ada LovelaceMaintainer
  • GH
    Grace HopperReviewer

Presence

Avatar.Indicator adds a corner dot for availabilityonline, busy, focus, away, or offline. Each preset picks both the colour (a dedicated --noctis-color-presence-* role) and a default localized screen-reader label, so the dot is never a colour-only signal. A canvas-coloured ring keeps it legible against any photo; an offline teammate is often paired with the dimmed disabled state.

ALOnlineGHBusyKJIn focusJCAwayRPOffline

Status

Status is a separate concept from presence — a contextual badge (approved, declined, locked), typically placed in the top corner with placement="top". It reuses the system's success/danger/muted roles. Override the announced text with aria-label when the preset's default label doesn't fit the context.

ALApprovedGHDeclinedKJLocked

Group

Avatar.Group stacks avatars into a facepile — overlapped, each with a canvas-coloured separating ring so it reads against the next. Set size/shape on the group and every child inherits them. Past max avatars, the rest collapse into a +N overflow chip (announced as "N more members"). The chip is non-interactive — Avatar represents avatars, not controls — so to make the overflow reveal the hidden members, wrap the group in your own trigger. Overlap leans the correct way in RTL automatically; spacing (cozy by default, or tight) tunes how far they overlap.

ALGHKJJC3 more members

As a trigger

A clickable avatar — the account menu being the canonical case — must be a real <button>. Render Avatar.Root as one (so focus, role, and keyboard activation come from the element) and use it as a Menu.Trigger; it shows a focus-visible ring that follows its shape. Mark the active account with data-selected for the accent selection ring.

Loading

Avatar.Skeleton is an opt-in placeholder shown only while an Avatar.Image is actively loading — a muted pulse, distinct from the permanent initials fallback (shown on error or when there's no image). It clears once the image loads, which cross-fades in. The pulse drops to a static fill under reduced motion. Use Reload image to refetch: a cached image resolves instantly and skips the placeholder, so the demo cache-busts each load to make the loading window visible.

BL

Accessibility

Avatars are two-mode, and choosing the right mode avoids double-announcement:

  • Decorative (the default — an avatar beside a visible name, as in Avatar item): give Avatar.Image an empty alt and add no role/label. The adjacent name is the accessible label.
  • Informative (a standalone avatar with no surrounding text, e.g. an account button): pass aria-label to Avatar.Root. It then stamps role="img" and announces itself once; keep the inner image's alt empty.

Avatar.Indicator always renders a visually-hidden label (Online, Approved, …) so the dot is announced — a colour-only signal is invisible to assistive tech. Override it with aria-label. Avatar.Group is a role="group" and requires an aria-label; its +N overflow chip carries a visually-hidden "N more members" so the count isn't silently dropped (the chip is non-interactive — wrap the group in your own trigger to make the hidden members reachable). A clickable avatar is always a real <button> (see As a trigger) — never an aria-hidden or div with a click handler.

Anatomy

Compose the avatar from its three parts. Avatar.Root is a Base UI Avatar, so the image-to-fallback swap on a missing or failed load comes for free.

  • Avatar.Root — the box; owns the shared size and shape, plus the ring and disabled flags. Pass aria-label to make it informative (role="img").
  • Avatar.Image — the profile photo. Crops to cover the box and follows its shape; pass src and alt (empty in the decorative case). Cross-fades in on load.
  • Avatar.Fallback — shown when no image loads. Pass initials or a glyph as children, and a seed to pick a stable bg-avatar-N swatch.
  • Avatar.Indicator — a corner presence/status dot. Pass a preset and an optional placement; it announces a localized label.
  • Avatar.Skeleton — an opt-in loading placeholder, shown only while an image loads.
  • Avatar.Group — a facepile of overlapped avatars; renders an Avatar.GroupOverflow +N chip past its max.

Every rendered part carries a data-slot (noctis-avatar on the box, noctis-avatar-image on the photo, noctis-avatar-fallback on the fallback, noctis-avatar-indicator on the dot, noctis-avatar-skeleton on the placeholder, noctis-avatar-group on the facepile) for host-side styling — pair it with the data-size/data-shape axes the box stamps, the data-avatar-index the fallback carries, and the data-preset/data-placement the indicator carries.

On surfaces

The same control re-tuned across the elevation scopes — the root canvas, an elevated panel, a menu, and a sunken well. It stays legible on every layer.

root
ALGHKJRP
elevated
ALGHKJRP
menu
ALGHKJRP
sunken
ALGHKJRP

Design tokens

Generated from the component's declaration — the same graph that mints the CSS, so a variable name or its resolution default can't drift. The minted tokens are the public override seam: set one on any ancestor and every avatar in that region retunes — e.g. .roster { --noctis-avatar-size: 2rem; } shrinks the avatars beneath it. Knobs that aren't minted are reached through the part's data-slot. See Customization for the full override ladder and Tokens for the whole graph.

Token

API reference

Generated from the component's types — every prop, type, default, and description comes straight from the source. Each part gets its own table; the Root and Image forward the Base UI Avatar props they own. Expand a row for the full type and description.

Avatar.Root

Prop

Avatar.Image

Prop

Avatar.Fallback

Prop

Avatar.Indicator

Prop

Avatar.Skeleton

Prop

Avatar.Group

Prop

Avatar.GroupOverflow

Prop

AttributeDescription
data-slotThe root avatar element.
data-sizeThe size scale — `2xs` | `xs` | `sm` | `md` | `lg` | `xl`; the generated layer keys the per-size internals off it.
data-shapeThe shape — `circle` (default, fully round) | `rounded` (rounded corners).
data-avatar-index`1`–`10`, the stable hashed swatch index the fallback fill reads its `bg-avatar-N` role from.
data-disabledPresent when the avatar is dimmed/inactive — gates interactive states and applies the disabled opacity.
data-ringPresent when the avatar carries a hairline ring separating it from its surface.
data-presetThe indicator preset — a presence or status value; the dot reads its fill role from it.
data-placementThe indicator's logical corner — `top` | `bottom` (default).
data-spacingThe group's overlap tightness — `tight` | `cozy` (default).
data-avatar-overflowMarks the group's `+N` overflow chip (a non-interactive avatar-shaped count).