Skip to content

Avatar

.bp-avatar renders on a native <img> element. When the image loads, object-fit: cover crops it to a circle. When the image fails or src is empty, the browser renders the alt text — styled by the same flex layout — producing a CSS-only initials fallback with no JavaScript or extra markup. Size variants override a single --avatar-size token that drives width, height, and font-size together. .bp-avatar-group stacks multiple avatars with a negative overlap and a ring border for separation.

With image

Jane Doe
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=1" alt="Jane Doe" width="40" height="40" />

When src is empty or the image fails to load, the browser renders alt text inside the styled flex container. Use one or two initials as the alt value.

Initials fallback (broken or empty src)

JD AL MK
<img class="bp-avatar" src="" alt="JD" width="40" height="40" />
<img class="bp-avatar" src="" alt="AL" width="40" height="40" />
<img class="bp-avatar" src="" alt="MK" width="40" height="40" />

When the user’s name is visible in adjacent text, pass alt="" so screen readers skip the redundant image.

Decorative avatar alongside visible name

Jane Doe
<style>
.demo-avatar-identity { display: inline-flex; align-items: center; gap: 0.5rem; font-weight: 600; }
</style>
<div class="demo-avatar-identity">
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=2" alt="" width="40" height="40" />
Jane Doe
</div>

All size variants override --avatar-size only. Font size scales automatically via calc().

Size variants

XS SM MD LG XL
<style>
.demo-avatar-sizes { display: inline-flex; align-items: center; gap: 1rem; }
</style>
<div class="demo-avatar-sizes">
<img class="bp-avatar bp-avatar--xs" src="" alt="XS" width="24" height="24" />
<img class="bp-avatar bp-avatar--sm" src="" alt="SM" width="32" height="32" />
<img class="bp-avatar" src="" alt="MD" width="40" height="40" />
<img class="bp-avatar bp-avatar--lg" src="" alt="LG" width="48" height="48" />
<img class="bp-avatar bp-avatar--xl" src="" alt="XL" width="64" height="64" />
</div>

Square avatar

Team logo
<img class="bp-avatar bp-avatar--square" src="https://i.pravatar.cc/80?img=3" alt="Team logo" width="40" height="40" />

Wrap avatars in .bp-avatar-group. Use role="group" and aria-label to give the group a collective name for screen readers. The overflow count avatar uses an intentionally empty src so the +N alt text always renders.

Avatar group with overflow count

Alice Bob Carol +3
<style>
.demo-avatar-group-wrap { display: inline-flex; align-items: center; gap: 0.75rem; }
</style>
<div class="demo-avatar-group-wrap">
<div class="bp-avatar-group" role="group" aria-label="Project members">
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=10" alt="Alice" width="40" height="40" />
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=11" alt="Bob" width="40" height="40" />
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=12" alt="Carol" width="40" height="40" />
<img class="bp-avatar bp-avatar--overflow" src="" alt="+3" width="40" height="40" />
</div>
</div>
VariableDefaultDescription
--avatar-size2.5remWidth and height of the avatar
--avatar-radius9999pxBorder radius — 9999px produces a circle
--avatar-font-sizecalc(var(--avatar-size, 2.5rem) * 0.4)Initials text size — scales with --avatar-size
--avatar-font-weight600Initials text weight
--avatar-bgvar(--bp-color-neutral-200, #e5e7eb)Fallback background shown behind initials or on error
--avatar-colorvar(--bp-color-neutral-700, #374151)Initials text color
--avatar-border-width2pxRing border width applied in groups
--avatar-border-colorvar(--bp-color-bg, #fff)Ring border color — should match surrounding surface
--avatar-group-overlap-0.75remNegative margin-inline-start for stacking in groups
--avatar-overflow-bgvar(--bp-color-neutral-300, #d1d5db)Background for the +N overflow count avatar
--avatar-overflow-colorvar(--bp-color-neutral-800, #1f2937)Text color for the +N overflow count avatar
Class--avatar-size
bp-avatar--xs1.5rem
bp-avatar--sm2rem
(default)2.5rem
bp-avatar--lg3rem
bp-avatar--xl4rem

Override public tokens via a scoped CSS class — never via style="".

Custom teal avatar with branded background

BP
User one User two User three
<style>
.demo-avatar--brand {
--avatar-bg: #0d9488;
--avatar-color: #fff;
--avatar-font-weight: 700;
}
.demo-avatar--tight-group {
--avatar-group-overlap: -1.25rem;
--avatar-border-color: #f0fdf4;
}
</style>
<img class="bp-avatar demo-avatar--brand" src="" alt="BP" width="40" height="40" />
<div class="bp-avatar-group demo-avatar--tight-group" role="group" aria-label="Tight group example">
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=20" alt="User one" width="40" height="40" />
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=21" alt="User two" width="40" height="40" />
<img class="bp-avatar" src="https://i.pravatar.cc/80?img=22" alt="User three" width="40" height="40" />
</div>
No axe violations tested 2026-05-12
Scenarioalt valueReason
Avatar is the sole identifier for the userFull name — "Jane Doe"Screen reader announces who the avatar represents
Adjacent visible text already names the user"" (empty)Avoids redundant announcement; image is decorative
Initials fallbackInitials — "JD"Initials text renders visually and is the accessible name
Overflow countCount — "+3"Screen reader announces the count

Wrap avatar groups in role="group" with a descriptive aria-label (e.g. "Project members"). This groups the individual <img> labels together for screen readers without hiding any of them.

alt="" marks an image as decorative. Use this when the user’s name appears as adjacent visible text — do not use it when the avatar is the only way to identify the person.

APIAvailabilityUsed forWithout itPolyfill
object-fit Widely available Baseline 2020 Crops image to fill the avatar without distortionImage may stretch or letterboxNone — widely supported
alt text rendering (broken image) Widely available Baseline 2020 CSS-only initials fallback when src is empty or failsNo text displayed; background color remainsNone needed — fallback degrades gracefully

Safari variance: Safari may display a broken-image icon alongside the alt text when src is a non-empty URL that fails to load. When src="" (intentionally empty, as used for the overflow avatar and the initials pattern), Safari suppresses the broken-image icon and renders only the alt text — matching the intended design. For the initials fallback, always use src="" rather than a deliberately invalid URL.

  • --_size, --_radius, --_font-size, --_font-weight, --_bg, --_color, --_border-width, --_border-color — component-private variables resolved on the root .bp-avatar selector. Do not set --_* variables directly.
  • object-fit: cover is applied directly on .bp-avatar. When the image loads the browser respects object-fit on <img>. When it fails the flex layout takes over and centers alt text.
  • Size variants override --avatar-size only. The private --_font-size recomputes via calc() automatically — no per-variant font-size override is needed.
  • Group stacking uses isolation: isolate on .bp-avatar-group to create a new stacking context, preventing z-index leakage from surrounding content.
  • The --overflow modifier overrides --avatar-bg and --avatar-color using the public overflow tokens. It does not change structure — the element is still a plain .bp-avatar.