Skip to content
Nizivo UI

Avatar

A person's or store's photo with an initials fallback that needs no script, and AvatarGroup, a stack of avatars and a count announced as one item ("Maya, Jonah, Priya, and 4 more").

Server component, no client JS

Import

import { Avatar, AvatarGroup } from '@nizivo/react/avatar';

// Once per app (Getting started), after
// @nizivo/tokens/tokens.css and @nizivo/react/css/base.css
import '@nizivo/react/css/avatar.css';

Static or interactive

Server. It ships no client JavaScript when a Server Component renders it, in every Next.js build mode; its code is bundled only when a client component (a 'use client' file) imports it. The initials are always in the server HTML and the photo is laid over them with alt="", so in Chromium and Firefox a photo that fails to load shows the initials with no onError handler and no hydration. WebKit (Safari) draws its own broken-image mark over the middle of the initials, and no script-free markup avoids it (D-bf); test/browser/avatar.spec.tsx samples the pixels in all three engines and pins that. How to choose.

In a client app (a Vite or React Router single-page app, or a 'use client' file) it is an ordinary React component: event handlers, refs and state work as usual. In a client app.

Names

The avatar is role="img" named by name; the image inside it has alt="" and the initials are aria-hidden. When the name is printed next to the avatar, pass decorative: the avatar is then aria-hidden. Inside an AvatarGroup every avatar is decorative and the group is one role="img" named by the list of names, joined with Intl.ListFormat in the group's locale.

A photo that fails to load in WebKit

The fallback to the initials needs no script in Chromium and Firefox. WebKit (Safari) is different: when src fails to load it draws its own broken-image mark, a "?" glyph, over the middle of the initials, and nothing script-free avoids it. No CSS can tell a broken image from a loaded one in WebKit; an SVG <image> shows the mark in Chromium and WebKit too, and <object> is blocked by a strict Content Security Policy's object-src (D-bf, kept by the maintainer's decision M42). So:

  • pass src (or image) only when the photo is known to load, for example a URL your server has just checked, or one from your own storage;
  • when it may be gone, leave src out and the initials render, the same markup in every engine.

Examples

Group

Three faces and a count, read as one item: "Maya Rao, Jonah Okafor, Priya Shah, and 4 more".

import type { JSX } from 'react';
import { Avatar, AvatarGroup } from '@nizivo/react/avatar';

/** A stand-in portrait (an inline SVG), so the example needs no image file. */
const PHOTO =
  'data:image/svg+xml,' +
  encodeURIComponent(
    '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><rect width="64" height="64" fill="#c9b8a6"/>' +
      '<circle cx="32" cy="26" r="12" fill="#8a6f5a"/><rect x="12" y="42" width="40" height="30" rx="20" fill="#8a6f5a"/></svg>',
  );

/** A photo, the initials fallback at every size, and a decorative avatar next to a printed name. */
export function AvatarExample(): JSX.Element {
  return (
    <div>
      <Avatar name="Maya Rao" src={PHOTO} size="lg" />
      <Avatar name="Jonah Okafor" size="sm" />
      <Avatar name="Jonah Okafor" />
      <Avatar name="Jonah Okafor" size="lg" />
      <Avatar name="Jonah Okafor" size="xl" />
      <p>
        <Avatar name="Priya Shah" decorative /> Priya Shah
      </p>
    </div>
  );
}

export function AvatarGroupExample(): JSX.Element {
  return (
    <AvatarGroup total={7}>
      <Avatar name="Maya Rao" src={PHOTO} />
      <Avatar name="Jonah Okafor" />
      <Avatar name="Priya Shah" src={PHOTO} />
    </AvatarGroup>
  );
}

Props

Avatar

A person's or store's photo laid over their initials, with no script: the initials are always rendered, so a missing photo needs no onError. Known limit: a src that fails to load shows WebKit's (Safari's) broken-image mark over the initials, with no script-free fix; pass src only when it is known to load, or leave it out and the initials show.

Server component Renders data-slot="avatar" with the class nz-avatar. Props: AvatarProps. Source: src/avatar/avatar.tsx.

NameTypeDefaultDescription
decorativebooleanfalse

The name is printed next to the avatar, so the avatar is hidden from assistive technology (Figma: alt="" when the name is printed next to it).

imageReactElement<{ className?: string | undefined; }>–

A framework image element in place of src, for example image={<NextImage src={photo} alt="" />}. It is cloned with the image slot's class and alt="", and laid over the initials like src.

initialsstring–

Replaces the initials derived from name (the first letters of the first and last words). Figma: at most two letters.

namerequiredstring–

The person's or store's name. It is the avatar's accessible name (unless decorative) and the source of the initials.

renderRenderProp<AvatarState>–

Composition of the root <span>.

sizeAvatarSize
"sm""md""lg""xl"
'md'
sizesstring–
srcstring–

The photo. Without it (or image), the initials show. Pass it only when the image is known to load: if it fails, Chromium and Firefox show the initials, but WebKit (Safari) draws its broken-image mark over them, and no script-free markup avoids that. For a URL that may be gone, check it on the server and leave src out (the initials render), or render the initials alone.

srcSetstring–

Passed to the <img> with src.

  • Also takes every attribute of <span> except children. (Omit<ComponentPropsWithRef<"span">, "children">)

render takes an element, or, in client code, a function of the props and this state (AvatarState):

NameTypeDefaultDescription
decorativerequiredboolean–
imagerequiredboolean–

An image source or image element was given.

sizerequiredAvatarSize
"sm""md""lg""xl"
–

AvatarGroup

A stack of avatars and a count, announced as one item (Figma: "Maya, Jonah, Priya and 4 more"): the root is role="img" named by the list of names, and every avatar inside is decorative.

Server component Renders data-slot="avatar-group" with the class nz-avatar-group. Props: AvatarGroupProps. Source: src/avatar/avatar.tsx.

NameTypeDefaultDescription
childrenReactNode–

Avatar elements.

labelsPartial<AvatarGroupLabels>–
localestring'en-US'

BCP 47 tag for the count and the list of names.

maxnumber3

How many avatars to show before the count. Figma: up to 3.

renderRenderProp<AvatarGroupState>–
sizeAvatarSize
"sm""md""lg""xl"
'md'

Applied to every avatar and the count.

totalnumberthe number of avatars

Everyone in the group, when it is more than the avatars passed (the server sends three faces and a count).

  • Also takes every attribute of <span>; children is redeclared above. (ComponentPropsWithRef<"span">)

render takes an element, or, in client code, a function of the props and this state (AvatarGroupState):

NameTypeDefaultDescription
hiddenrequirednumber–

People not shown as an avatar.

sizerequiredAvatarSize
"sm""md""lg""xl"
–

Other exports

AvatarGroupLabels type

import type { AvatarGroupLabels } from '@nizivo/react/avatar'

AvatarGroup's own strings (§16.4): serialisable, English defaults. {count} is replaced by the formatted count, and a PluralLabel ({ one, few, many, other }, the locale's CLDR categories) picks its template by that count through formatLabel.

NameTypeDefaultDescription
morerequiredstring | PluralLabel'{count} more'

The count's words in the group's accessible name ("Maya, Jonah, Priya and 4 more").

overflowrequiredstring | PluralLabel'+{count}'

The visible count after the shown avatars.

AvatarGroupProps type

import type { AvatarGroupProps } from '@nizivo/react/avatar'

The props of AvatarGroup, listed above.

AvatarGroupState type

import type { AvatarGroupState } from '@nizivo/react/avatar'

The render state of AvatarGroup, listed above.

AvatarProps type

import type { AvatarProps } from '@nizivo/react/avatar'

The props of Avatar, listed above.

AvatarSize type

import type { AvatarSize } from '@nizivo/react/avatar'

Figma "Size": Sm 24, Md 32, Lg 40, XL 56 px.

type AvatarSize = "sm" | "md" | "lg" | "xl"

AvatarState type

import type { AvatarState } from '@nizivo/react/avatar'

The render state of Avatar, listed above.

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

SlotRendered byData attributes
avatar
.nz-avatar
Avatar
root (takes render)
  • data-size: "sm""md""lg""xl" ← size
    The size prop; values in each component manifest
avatar-group
.nz-avatar-group
AvatarGroup
root (takes render)
  • data-size: "sm""md""lg""xl" ← size
    The size prop; values in each component manifest
avatar-group-more
.nz-avatar-group-more
AvatarGroup
inner element (CSS only)
none
avatar-image
.nz-avatar-image
Avatar
inner element (CSS only)
none
avatar-initials
.nz-avatar-initials
Avatar
inner element (CSS only)
none

CSS hooks

Set a hook on the component's class or any ancestor to restyle it without specificity games; leave it unset for the default shown.

HookDefaultRead as
--nz-avatar-bg--nz-bg-brand-muted
  • background on .nz-avatar
--nz-avatar-fg--nz-text-brand
  • color on .nz-avatar
--nz-avatar-font
  • default: var(--nz-font-label-s)
  • data-size="lg": var(--nz-font-label-m)
  • data-size="xl": var(--nz-font-label-l)
  • font on .nz-avatar
--nz-avatar-group-more-bg--nz-bg-muted
  • background on .nz-avatar-group-more
--nz-avatar-group-more-fg--nz-text-secondary
  • color on .nz-avatar-group-more
--nz-avatar-group-ring--nz-bg-surface
  • box-shadow on .nz-avatar-group > .nz-avatar
  • box-shadow on .nz-avatar-group > .nz-avatar-group-more
--nz-avatar-radius--nz-radius-full
  • border-radius on .nz-avatar
--nz-avatar-size
  • default: var(--nz-space-8)
  • data-size="lg": var(--nz-space-10)
  • data-size="sm": var(--nz-space-6)
  • data-size="xl": calc(var(--nz-space-12) + var(--nz-space-2))
  • block-size on .nz-avatar
  • inline-size on .nz-avatar

Layers: nz.components. Classes: .nz-avatar, .nz-avatar-group, .nz-avatar-group-more, .nz-avatar-image, .nz-avatar-initials.

Tokens this stylesheet reads (18)

--nz-bg-brand-muted, --nz-bg-muted, --nz-bg-surface, --nz-border-width-focus, --nz-font-label-l, --nz-font-label-m, --nz-font-label-s, --nz-radius-full, --nz-space-10, --nz-space-12, --nz-space-2, --nz-space-6, --nz-space-8, --nz-text-brand, --nz-text-secondary, --nz-tracking-label-l, --nz-tracking-label-m, --nz-tracking-label-s

Accessibility

Nothing in this component takes focus or keyboard input.

Keyboard

None.

Figma

Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.

On this page