Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
99b4dc3
feat: add avatar utility primitives
pawelgrimm May 26, 2026
5942fd4
fix: preserve unicode avatar initials
pawelgrimm May 26, 2026
a3527b7
fix: preserve avatar utility type checks
pawelgrimm May 26, 2026
b4e89bc
fix: normalize avatar initials before comparison
pawelgrimm May 26, 2026
cdbe28d
feat: replace avatar primitive API
pawelgrimm May 26, 2026
329ea17
fix: retry avatar image after prop reset
pawelgrimm May 26, 2026
9e7ad43
docs: update avatar stories
pawelgrimm May 26, 2026
1d3d104
docs: add avatar product wrappers
pawelgrimm May 26, 2026
f35cade
fix: preserve avatar initials and fallback examples
pawelgrimm May 26, 2026
9b66cd7
fix: cap avatar initials after uppercase expansion
pawelgrimm May 26, 2026
589a075
fix: address avatar review findings
pawelgrimm May 26, 2026
d745858
fix: type avatar story playground args
pawelgrimm May 26, 2026
c37d041
refactor: inline avatar accessibility props
pawelgrimm May 26, 2026
ae2957a
refactor: rely on native avatar srcset selection
pawelgrimm May 26, 2026
ec3dd2a
fix: retry avatar srcset candidates after load failure
pawelgrimm May 26, 2026
ad8a98d
refactor: simplify avatar initials generation
pawelgrimm May 26, 2026
5da1d9b
docs: document avatar public api
pawelgrimm May 26, 2026
8a86a03
refactor: clarify avatar image identity key
pawelgrimm May 26, 2026
fa0b235
refactor: Clean up and clarify
pawelgrimm May 26, 2026
49d18c0
refactor: Use Box props where possible, restructure CSS
pawelgrimm May 26, 2026
4392eb3
feat: Implement new stories
pawelgrimm May 26, 2026
8b1be8b
fix: Add inset border to avatars
pawelgrimm May 26, 2026
b9d130f
fix: handle empty avatar state
pawelgrimm May 26, 2026
e751657
refactor: Create improved avatar docs
pawelgrimm May 27, 2026
211dd34
Update avatar meta color tokens
pawelgrimm May 27, 2026
bdd27c5
refactor: Rework meta color CSS custom props
pawelgrimm May 27, 2026
f0d2a2c
docs: add avatar migration guidance
pawelgrimm May 27, 2026
5cc19fb
fix: Add ref + passthrough props support
pawelgrimm May 27, 2026
2bdf3d3
fix: Only set aria-hidden on container
pawelgrimm May 27, 2026
29d09e2
test: add avatar axe coverage
pawelgrimm May 27, 2026
b12ee97
fix: normalize avatar fallback labels
pawelgrimm May 27, 2026
76abc62
refactor: apply avatar meta colors to initials
pawelgrimm May 27, 2026
3587011
refactor: simplify avatar initials splitting
pawelgrimm May 27, 2026
a98b772
perf: skip avatar source filtering when unchanged
pawelgrimm May 27, 2026
8d673d2
refactor: reuse avatar size constants in stories
pawelgrimm May 27, 2026
e66680f
docs: render avatar migration table as markdown
pawelgrimm May 27, 2026
ab3eef6
feat: support polymorphic avatar root
pawelgrimm May 27, 2026
10b13ec
refactor: move avatar size styles to css
pawelgrimm May 28, 2026
7f9421e
refactor: reset only AvatarImage when key changes
pawelgrimm May 28, 2026
30fca01
refactor: More aria-hidden to AvatarImage
pawelgrimm May 28, 2026
79082f0
test: extract avatar image failure helper
pawelgrimm May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 0 additions & 11 deletions src/avatar/__snapshots__/avatar.test.tsx.snap

This file was deleted.

189 changes: 189 additions & 0 deletions src/avatar/avatar.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import {
Canvas,
ColorItem,
ColorPalette,
Controls,
Markdown,
Meta,
Subtitle,
Title,
} from '@storybook/addon-docs/blocks'

import * as AvatarStories from './avatar.stories'

<Meta of={AvatarStories} />

<Title />

<Subtitle>Image, initials, and empty-state avatar primitive.</Subtitle>

## Basic usage

Use `Avatar` for people by default. Pass `size`, `name`, and an optional
`image`; `name` supplies the default accessible label, the initials fallback,
and the deterministic meta color used when initials render.
Comment thread
pawelgrimm marked this conversation as resolved.

<Canvas of={AvatarStories.Default} />

## Migrating from the legacy API

The previous Avatar API accepted `user`, `avatarUrl`, `colorList`, string or
responsive `size` values, and a deprecated `className`. The current API uses
direct identity props instead:

<Markdown>{`
| Legacy prop | Current API |
| ------------------------------ | ------------------------------------------------------------------------ |
| \`user.name\` | \`name\` |
| \`avatarUrl\` | \`image\` |
| \`user.email\` | No replacement. Email is no longer used for initials or color selection. |
| \`colorList\` | Customize the CSS custom properties listed below. |
| \`size="l"\` or responsive sizes | Pass one supported numeric CSS-pixel \`size\`. |
| \`className\` | \`exceptionallySetClassName\` |
`}</Markdown>

```tsx
<Avatar size={36} name={user.name} image={avatarUrl} exceptionallySetClassName={className} />
```

## Initials fallback

When `image` is not supplied, cannot be resolved, or every responsive image
candidate fails, Avatar falls back to initials derived from `name`. Names are
normalized before initials are generated.

<Canvas of={AvatarStories.InitialsFallback} />

## Workspace avatars

Use `shape="rounded"` for workspace-like entities. Product code can wrap
Avatar with a small convention component when a surface always represents the
same kind of entity.

<Canvas of={AvatarStories.WorkspaceAvatar} />

## Image sources

Pass a string for a single image URL, or a source map keyed by intrinsic image
width. Source maps render native `srcSet` width descriptors and a `sizes` hint
based on the selected avatar size.

<Canvas of={AvatarStories.ImageSources} />

## Sizes

Avatar supports a fixed set of CSS pixel sizes. Use one of the supported
numeric values instead of styling the avatar dimensions from the outside.

<Canvas of={AvatarStories.Sizes} />

## Accessibility

Images default to `name` for alt text. Pass `alt` when the visual needs a more
specific label, and pass `alt=""` when the avatar is decorative.

<Canvas of={AvatarStories.Accessibility} />

## Playground

Use the controls to inspect the component API and common image/name
combinations.

<Canvas of={AvatarStories.Playground} />

### API

<Controls of={AvatarStories.Playground} />

## Custom properties

The following CSS custom properties are available to customize the avatar
component appearance. The values shown below are the default values.

<Canvas of={AvatarStories.MetaColors} />

### Customizable properties

#### Avatar colors

<ColorPalette>
<ColorItem title="--reactist-avatar-initials-color" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-border-tint" colors={['#0000001a']} />
<ColorItem title="--reactist-avatar-empty-fill" colors={['#e6e6e6']} />
</ColorPalette>

#### Avatar meta colors

<ColorPalette>
<ColorItem title="--reactist-avatar-meta-0-fill" colors={['#b8255f']} />
<ColorItem title="--reactist-avatar-meta-0-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-1-fill" colors={['#dc4c3e']} />
<ColorItem title="--reactist-avatar-meta-1-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-2-fill" colors={['#f48318']} />
<ColorItem title="--reactist-avatar-meta-2-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-3-fill" colors={['#fecf05']} />
<ColorItem title="--reactist-avatar-meta-3-on-idle-tint" colors={['#202020']} />
<ColorItem title="--reactist-avatar-meta-4-fill" colors={['#aeb83a']} />
<ColorItem title="--reactist-avatar-meta-4-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-5-fill" colors={['#7ecc48']} />
<ColorItem title="--reactist-avatar-meta-5-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-6-fill" colors={['#369307']} />
<ColorItem title="--reactist-avatar-meta-6-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-7-fill" colors={['#52ccb8']} />
<ColorItem title="--reactist-avatar-meta-7-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-8-fill" colors={['#148fad']} />
<ColorItem title="--reactist-avatar-meta-8-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-9-fill" colors={['#3ab9e2']} />
<ColorItem title="--reactist-avatar-meta-9-on-idle-tint" colors={['#202020']} />
<ColorItem title="--reactist-avatar-meta-10-fill" colors={['#96c3eb']} />
<ColorItem title="--reactist-avatar-meta-10-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-11-fill" colors={['#2a67e2']} />
<ColorItem title="--reactist-avatar-meta-11-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-12-fill" colors={['#692ec2']} />
<ColorItem title="--reactist-avatar-meta-12-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-13-fill" colors={['#ac30cc']} />
<ColorItem title="--reactist-avatar-meta-13-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-14-fill" colors={['#eb96c8']} />
<ColorItem title="--reactist-avatar-meta-14-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-15-fill" colors={['#e05095']} />
<ColorItem title="--reactist-avatar-meta-15-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-16-fill" colors={['#c9766f']} />
<ColorItem title="--reactist-avatar-meta-16-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-17-fill" colors={['#808080']} />
<ColorItem title="--reactist-avatar-meta-17-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-18-fill" colors={['#999999']} />
<ColorItem title="--reactist-avatar-meta-18-on-idle-tint" colors={['#ffffff']} />
<ColorItem title="--reactist-avatar-meta-19-fill" colors={['#ccae96']} />
<ColorItem title="--reactist-avatar-meta-19-on-idle-tint" colors={['#ffffff']} />
</ColorPalette>

### Component-owned variables

Avatar's size classes set these variables from the `size` prop. They are
listed for completeness, but consumers should prefer the component props
instead of overriding them directly.

```css
.avatar {
--reactist-avatar-size: 36px;
--reactist-avatar-rounded-radius: 5px;
}
```

## What the consumer owns

- **Identity data** — choose the `name`, `image`, and any custom `alt` text.
- **Source selection** — provide either one URL or a width-keyed source map.
- **Entity convention** — choose `shape="circle"` for people and
`shape="rounded"` for workspace-like entities.
- **Decorative usage** — pass `alt=""` when surrounding UI already names the
represented entity.
- **Persistence and fetching** — Avatar does not load, cache, or persist remote
user/workspace data.

## Accessibility

- `name` becomes the default image `alt` text and initials `aria-label`.
- `alt` overrides the accessible label for both image and initials rendering.
- `alt=""` marks image and initials avatars as decorative.
- An avatar with no `name` and no `image` renders as an empty decorative visual.
Loading
Loading