Avatar
A Base UI Avatar for a person or organization beside a byline, comment, member list or account menu: a circular photo, seal or initials face inside a ring.
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarImage,
AvatarStatus,
} from '@fairgarden-private/design/components/Avatar'
Give the image alt text with the name, or empty alt when the name is beside it. AvatarFallback is the initials face: a nested light face with one or two caps initials, shown until the photo loads or if it fails; never color-code it. AvatarStatus puts a status glyph on its own disc at the frame's bottom end; show the state in words too, since presence is never a color dot alone. As a link or menu trigger, a ring up to 40 px steps to --primary12 at the same weight on hover; from 64 px it does not change. Photos print in grayscale inside a 0.75 pt ring.
Sizes, initials, status and groups
Sizes, initials, status and groups
Sizes are xs 24, sm 32, md 40 (default), lg 64 and xl 128 px, fixed at every width. Up to 40 px the ring is a --role-rule hairline; from 64 px it is --border-size-2 in the text ink. AvatarGroup overlaps its avatars by a quarter, separates them with a halo ring and ends with a "+N" avatar: three avatars at base, up to five from 1024 px.
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarImage,
AvatarStatus,
} from '@fairgarden-private/design/components/Avatar'
import { portrait } from '../portrait'
import styles from './variants.module.css'
const sizes = ['xs', 'sm', 'md', 'lg', 'xl'] as const
const people = ['Ana Díaz', 'Ben Okafor', 'Chloe Park', 'Dev Rao', 'Eli Moss', 'Fay Lund']
function initials(name: string) {
return name
.split(' ')
.map((part) => part[0])
.join('')
}
/** Five fixed sizes; the initials face shows until the photo loads, or if it fails. */
export function AvatarVariants() {
return (
<div className={styles.stack}>
<div className={styles.row}>
{sizes.map((size) => (
<Avatar key={size} size={size}>
<AvatarImage src={portrait} alt="Ana Díaz" />
<AvatarFallback>AD</AvatarFallback>
</Avatar>
))}
</div>
<div className={styles.row}>
{sizes.map((size) => (
<Avatar key={size} size={size}>
<AvatarFallback>BO</AvatarFallback>
</Avatar>
))}
</div>
<div className={styles.row}>
<Avatar size="lg">
<AvatarImage src={portrait} alt="" />
<AvatarFallback>AD</AvatarFallback>
<AvatarStatus status="success" label="Online" />
</Avatar>
<span className={styles.copy}>Ana Díaz · Online</span>
<Avatar size="lg">
<AvatarFallback>BO</AvatarFallback>
<AvatarStatus status="warning" label="Away" />
</Avatar>
<span className={styles.copy}>Ben Okafor · Away</span>
</div>
<AvatarGroup size="md" total={9} aria-label="Stewardship team">
{people.map((name) => (
<Avatar key={name}>
<AvatarFallback>{initials(name)}</AvatarFallback>
</Avatar>
))}
</AvatarGroup>
</div>
)
}
Primary scale
Primary scale
primary drives the ring. The initials face and status disc are their own light faces, so their inks never change.
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarImage,
AvatarStatus,
} from '@fairgarden-private/design/components/Avatar'
import { portrait } from '../portrait'
import styles from './color.module.css'
/** `primary` drives the ring; the initials face and status disc keep their own light face. */
export function AvatarColor() {
return (
<div className={styles.row}>
<Avatar size="md" primary="plum">
<AvatarImage src={portrait} alt="Ana Díaz" />
<AvatarFallback>AD</AvatarFallback>
</Avatar>
<Avatar size="lg" primary="plum">
<AvatarImage src={portrait} alt="Ana Díaz" />
<AvatarFallback>AD</AvatarFallback>
</Avatar>
<Avatar size="lg" primary="bronze">
<AvatarFallback>BO</AvatarFallback>
<AvatarStatus status="info" label="In a meeting" />
</Avatar>
</div>
)
}
On grounds
On paper and forest
paper
forest
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarImage,
AvatarStatus,
} from '@fairgarden-private/design/components/Avatar'
import { PresetGround } from '@/components/PresetGround'
import { portrait } from '../portrait'
import styles from './grounds.module.css'
const presets = ['paper', 'forest'] as const
/** Rings follow the ground; the initials face stays a light face; the group ring cuts a ground-colored gap. */
export function AvatarGrounds() {
return (
<div className={styles.row}>
{presets.map((preset) => (
<PresetGround key={preset} preset={preset} className={styles.face}>
<p className={styles.name}>{preset}</p>
<div className={styles.avatars}>
<Avatar size="md">
<AvatarImage src={portrait} alt="Ana Díaz" />
<AvatarFallback>AD</AvatarFallback>
</Avatar>
<Avatar size="lg">
<AvatarFallback>BO</AvatarFallback>
<AvatarStatus status="success" label="Online" />
</Avatar>
</div>
<AvatarGroup size="sm" aria-label="Volunteers">
<Avatar>
<AvatarImage src={portrait} alt="Ana Díaz" />
<AvatarFallback>AD</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>BO</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>CP</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>DR</AvatarFallback>
</Avatar>
</AvatarGroup>
</PresetGround>
))}
</div>
)
}
API Reference
Avatar
The circular frame and its ring. Compose AvatarImage (a photo or a
seal), AvatarFallback (1–2 initials, shown until the image loads or if
it fails) and an optional AvatarStatus. Give the image alt text with the
name, or empty alt when the name is adjacent. As a link or menu trigger,
wrap it (or pass render): on hover a ring up to 40 px steps to
--primary12 at the same weight.
| Prop | Type | Description |
|---|---|---|
primary | | Primary Radix scale: the ring. Never defaulted; omitted, it inherits the scope [D133]. |
secondary | | Secondary Radix scale, accepted for the shared contract; no part uses it. |
size | |
|
AvatarImage and AvatarFallback
The photo or seal, cropped to the circle. Prints in grayscale.
The initials face: a nested white face (--primary1) with 1–2 caps
initials in the UI sans at weight 700 and --primary12, the same on every
ground. Never color-code initials backgrounds.
AvatarStatus
The status glyph (§1.5.4, with its inner mark) on its own white disc at
the frame’s bottom end, --size-px-3, in --role-status of its status
scale.
| Prop | Type | Description |
|---|---|---|
label | | The state in words, e.g. “Away”: the glyph’s accessible name. Show the word beside the avatar too; presence is never a color dot alone. |
status | | The presence or state: info, success, warning or danger (§1.5.4). |
AvatarGroup
Overlapping avatars (−25%) separated by a --size-px-1 ring in
--role-halo, ending in a “+N” initials avatar: 3 avatars at base, up to
5 from 1024 px.
| Prop | Type | Description |
|---|---|---|
moreLabel | | Accessible name for the “+N” avatar; receives N. Default “N more”. |
primary | | Primary Radix scale for the group’s avatars. Never defaulted. |
secondary | | Secondary Radix scale, accepted for the shared contract; no part uses it. |
size | | Size of every avatar in the group. Default |
total | | How many people the group stands for, when more exist than the avatars passed. Default: the number of avatars. |
Additional types
AvatarFallbackProps
Props for AvatarFallback: Base UI Avatar Fallback props.
type AvatarFallbackProps = AvatarFallback.AvatarFallbackPropsavatarGroup
The group’s classes: its size publishes the overlap.
type avatarGroup = avatarGroupAvatarGroupProps
Props for AvatarGroup: div props, render, the size, the total and the color axes.
type AvatarGroupProps = React.ClassAttributes<HTMLDivElement> &
React.HTMLAttributes<HTMLDivElement> &
__type & {
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | null;
total?: number;
primary?:
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'ruby'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'ruby'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
moreLabel?: (count: number) => string;
}AvatarImageProps
Props for AvatarImage: Base UI Avatar Image props.
type AvatarImageProps = AvatarImage.AvatarImagePropsAvatarProps
Props for Avatar: Base UI Avatar Root props plus the size and color axes.
type AvatarProps = AvatarRootProps & {
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | null;
primary?:
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'ruby'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| null;
secondary?:
| 'olive'
| 'sage'
| 'slate'
| 'sand'
| 'gray'
| 'mauve'
| 'brown'
| 'bronze'
| 'gold'
| 'red'
| 'ruby'
| 'crimson'
| 'tomato'
| 'pink'
| 'plum'
| 'indigo'
| 'iris'
| 'violet'
| 'purple'
| 'amber'
| 'blue'
| 'cyan'
| 'grass'
| 'green'
| 'jade'
| 'lime'
| 'mint'
| 'orange'
| 'sky'
| 'teal'
| 'yellow'
| null;
}AvatarSize
type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'<'xs' | 'sm' | 'md' | 'lg' | 'xl' | null | undefined>avatarStatus
The status disc’s class.
type avatarStatus = avatarStatusAvatarStatusProps
Props for AvatarStatus: span props, the status and its word.
type AvatarStatusProps = {
/** The presence or state: info, success, warning or danger (§1.5.4). */
status: 'info' | 'success' | 'warning' | 'danger';
/**
* The state in words, e.g. "Away": the glyph's accessible name. Show the
* word beside the avatar too; presence is never a color dot alone.
*/
label?: string;
}Specification: DESIGN-SYSTEM.md §10.12 (avatar) and §1.5.4 (status).