Avatar
A user's photo or initials, with a stable color per name, a status dot and grouping.
'use client';
import { Avatar } from '@akhatmirzo/ui';
const people = [
'Sarvar Abduxoliqov',
'Malika Rahimova',
'Jasur Karimov',
"O'tkir Hoshimov",
'Dilnoza Yusupova',
'Rustam Qodirov',
];
export default function AvatarBasic() {
return (
<div className="flex flex-wrap items-center gap-3">
{people.map((name) => (
<Avatar key={name} name={name} />
))}
</div>
);
}
Import
import { Avatar, AvatarGroup } from '@akhatmirzo/ui';When to use
- To represent a person or an organization — comments, chat, table rows, the profile menu.
- Always pass
name, even with a photo: if the image fails, the initials and color come from the name, and screen readers read it. - One name, one color. The color is derived from the name, so people are recognizable by color in a list too.
- For many participants, use
AvatarGroupwithmax: the rest collapse into "+N".
Sizes and shape
size: xs 24, sm 32, md 40 (default), lg 48 and xl 64px. shape: circle (default)
for people, square for stores, organizations and projects.
'use client';
import { Avatar } from '@akhatmirzo/ui';
export default function AvatarSizes() {
return (
<div className="flex flex-col gap-4">
<div className="flex flex-wrap items-center gap-3">
<Avatar size="xs" name="Malika Rahimova" />
<Avatar size="sm" name="Malika Rahimova" />
<Avatar size="md" name="Malika Rahimova" />
<Avatar size="lg" name="Malika Rahimova" />
<Avatar size="xl" name="Malika Rahimova" />
</div>
<div className="flex flex-wrap items-center gap-3">
<Avatar size="sm" shape="square" name="Bahor Market" />
<Avatar size="md" shape="square" name="Bahor Market" />
<Avatar size="lg" shape="square" name="Bahor Market" />
</div>
</div>
);
}
Image and fallback
With src, the photo is shown; while it loads or if it fails, you see the initials. Without a
name either, a person icon (or your fallback) appears. The second avatar's image URL is broken
on purpose.


'use client';
import { Avatar } from '@akhatmirzo/ui';
export default function AvatarImage() {
return (
<div className="flex flex-wrap items-center gap-3">
<Avatar size="lg" src="https://github.com/Akhatmirzo.png" name="Akhatmirzo" />
<Avatar size="lg" src="/mavjud-emas.png" name="Gulnora Aliyeva" />
<Avatar size="lg" />
</div>
);
}
Status
status: online, offline or busy — a colored dot in the corner. It's also added to the
aria-label for screen readers: "Sarvar Abduxoliqov (onlayn)".
'use client';
import { Avatar } from '@akhatmirzo/ui';
export default function AvatarStatus() {
return (
<div className="flex flex-wrap items-center gap-4">
<Avatar name="Sarvar Abduxoliqov" status="online" />
<Avatar name="Malika Rahimova" status="offline" />
<Avatar name="Rustam Qodirov" status="busy" />
<Avatar name="Jasur Karimov" shape="square" size="lg" status="online" />
</div>
);
}
Group
AvatarGroup overlaps its avatars. size and shape pass from the group to its children;
anything beyond max becomes "+N".
'use client';
import { Avatar, AvatarGroup } from '@akhatmirzo/ui';
const team = [
'Sarvar Abduxoliqov',
'Malika Rahimova',
'Jasur Karimov',
'Dilnoza Yusupova',
'Rustam Qodirov',
'Gulnora Aliyeva',
'Bekzod Toshmatov',
];
export default function AvatarGroupDemo() {
return (
<AvatarGroup max={4} aria-label="Loyiha ishtirokchilari">
{team.map((name) => (
<Avatar key={name} name={name} />
))}
</AvatarGroup>
);
}
Props
Avatar
Avatar accepts every other <span> attribute except children.
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Image URL |
alt | string | — | Name for screen readers (falls back to name) |
name | string | — | Initials and background color are derived from it |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Size: 24 / 32 / 40 / 48 / 64px (inherits the group's inside a group) |
shape | 'circle' | 'square' | 'circle' | Shape (inherits the group's inside a group) |
status | 'online' | 'offline' | 'busy' | — | Status dot in the corner |
fallback | ReactNode | — | Shown when there is neither a name nor an image (default: a person icon) |
labels | { status?: Partial<Record<AvatarStatus, string>> } | { status: { online: 'onlayn', offline: 'oflayn', busy: 'band' } } | Status names for screen readers |
AvatarGroup
AvatarGroup accepts every other <div> attribute (aria-label ...).
| Prop | Type | Default | Description |
|---|---|---|---|
max | number | — | Maximum avatars to show; the rest become "+N" |
size | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | Size of every avatar |
shape | 'circle' | 'square' | 'circle' | Shape of every avatar |
labels | { more?: (count: number) => string } | — | Screen reader text for "+N" (default: "Yana N ta") |
Helper functions
The logic behind Avatar is exported on its own too:
import { getAvatarColor, getInitials } from '@akhatmirzo/ui';
getInitials('Sarvar Abduxoliqov'); // 'SA'
getInitials("o'tkir hoshimov"); // 'OH'
getAvatarColor('Sarvar Abduxoliqov'); // 'bg-danger-soft text-danger-soft-foreground'Data attributes
On the Avatar root: data-size, data-shape, data-status and data-state (loading ·
loaded · fallback).
Accessibility
role="img"with anaria-labeltaken fromaltorname, plus the status in brackets. The initials and image inside arearia-hidden, so screen readers say the full name, not "SA".- An avatar without a name (no
alt, noname) is treated as decoration and hidden completely. - The group is
role="group"; give it anaria-label("Project members"). The "+N" is alsorole="img"and reads "Yana N ta".