Primitives
Avatar
A round picture for a person, a team or an organization, with a fallback.
Primitives
A round picture for a person, a team or an organization, with a fallback.
import { Avatar, AvatarBadge, AvatarFallback } from 'ferry-ui'
export default function AvatarHero() {
return (
<div className="flex items-center gap-3">
<Avatar>
<AvatarFallback>MC</AvatarFallback>
<AvatarBadge className="bg-success" role="img" aria-label="Online" />
</Avatar>
<div className="flex flex-col">
<span className="text-sm font-medium text-foreground">Maya Chen</span>
<span className="text-[13px] text-foreground-light">maya@example.com</span>
</div>
</div>
)
}AvatarImage shows only after the picture loads. AvatarFallback fills the frame until then.AvatarGroup. Put the number of the others in AvatarGroupCount.Import the parts and put them together.
import { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from 'ferry-ui'
<AvatarGroup>
<Avatar>
<AvatarImage />
<AvatarFallback />
<AvatarBadge />
</Avatar>
<AvatarGroupCount />
</AvatarGroup>| Part | Role |
|---|---|
Avatar | The round frame. It sets the size. |
AvatarImage | The picture. It shows after the picture loads. |
AvatarFallback | Initials or an icon. It shows when there is no picture. |
AvatarBadge | A small dot at the bottom right of the avatar. |
AvatarGroup | A row of avatars that overlap. |
AvatarGroupCount | The last item of a group, for example "+5". |
Give the URL of the picture to AvatarImage. Put the initials of the person in AvatarFallback.
<Avatar>
<AvatarImage src={member.photo} alt={member.name} />
<AvatarFallback>MC</AvatarFallback>
</Avatar>If the picture fails, the fallback stays in view. The fallback can be initials or an icon. In this demo, the first picture cannot load.
import { Avatar, AvatarFallback, AvatarImage } from 'ferry-ui'
import { User } from 'lucide-react'
export default function AvatarFallbackDemo() {
return (
<>
<Avatar>
{/* This picture cannot load: the initials stay in view. */}
<AvatarImage src="data:image/png;base64,AA==" alt="Sam Patel" />
<AvatarFallback>SP</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>AL</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>
<User className="size-4" />
</AvatarFallback>
</Avatar>
</>
)
}To prevent a flash of the fallback on a fast network, set delayMs on AvatarFallback.
The size prop sets the diameter. The fallback text and the badge follow the size.
import { Avatar, AvatarFallback } from 'ferry-ui'
const SIZES = ['sm', 'md', 'lg'] as const
export default function AvatarSizes() {
return (
<>
{SIZES.map((size) => (
<Avatar key={size} size={size}>
<AvatarFallback>JR</AvatarFallback>
</Avatar>
))}
</>
)
}| Size | Diameter |
|---|---|
sm | 24px |
md | 32px (default) |
lg | 40px |
An avatar is round by default. For an organization, pass className="rounded-md". The picture and the fallback get the same radius.
import { Avatar, AvatarFallback } from 'ferry-ui'
import { Building2 } from 'lucide-react'
export default function AvatarOrganization() {
return (
<div className="flex items-center gap-3">
<Avatar className="rounded-md">
<AvatarFallback className="bg-primary-soft text-primary">
<Building2 className="size-4" />
</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-sm font-medium text-foreground">Acme</span>
<span className="text-[13px] text-foreground-light">12 members</span>
</div>
</div>
)
}AvatarBadge adds a dot at the bottom right of the avatar. It has the primary color by default. Set another color with a token class, such as bg-success.
The badge can hold an icon. The icon does not show at the sm size.
import { Avatar, AvatarBadge, AvatarFallback } from 'ferry-ui'
import { Check } from 'lucide-react'
export default function AvatarWithBadge() {
return (
<>
<Avatar size="lg">
<AvatarFallback>PN</AvatarFallback>
<AvatarBadge className="bg-success" role="img" aria-label="Online" />
</Avatar>
<Avatar size="lg">
<AvatarFallback>AW</AvatarFallback>
<AvatarBadge className="bg-warning" role="img" aria-label="Away" />
</Avatar>
<Avatar size="lg">
<AvatarFallback>OB</AvatarFallback>
<AvatarBadge className="bg-foreground-muted" role="img" aria-label="Offline" />
</Avatar>
<Avatar size="lg">
<AvatarFallback>DK</AvatarFallback>
<AvatarBadge role="img" aria-label="Verified">
<Check />
</AvatarBadge>
</Avatar>
</>
)
}AvatarGroup puts the avatars in a row where they overlap. Add AvatarGroupCount as the last child for the members that are not in view.
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount } from 'ferry-ui'
const MEMBERS = [
{ name: 'Maya Chen', initials: 'MC' },
{ name: 'Jordan Reyes', initials: 'JR' },
{ name: 'Priya Nair', initials: 'PN' },
{ name: 'Lucas Martin', initials: 'LM' },
]
export default function AvatarGroupDemo() {
return (
<AvatarGroup>
{MEMBERS.map((member) => (
<Avatar key={member.name}>
<AvatarFallback>{member.initials}</AvatarFallback>
</Avatar>
))}
<AvatarGroupCount>+5</AvatarGroupCount>
</AvatarGroup>
)
}AvatarGroupCount accepts text or an icon. With an icon, add hidden text for screen readers.
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount } from 'ferry-ui'
import { Plus } from 'lucide-react'
const MEMBERS = [
{ name: 'Maya Chen', initials: 'MC' },
{ name: 'Jordan Reyes', initials: 'JR' },
{ name: 'Priya Nair', initials: 'PN' },
]
export default function AvatarGroupIcon() {
return (
<AvatarGroup>
{MEMBERS.map((member) => (
<Avatar key={member.name} size="sm">
<AvatarFallback>{member.initials}</AvatarFallback>
</Avatar>
))}
<AvatarGroupCount>
<Plus aria-hidden="true" />
<span className="sr-only">12 more members</span>
</AvatarGroupCount>
</AvatarGroup>
)
}AvatarImage an alt text, usually the name of the person.AvatarBadge is a plain <span>. If the state matters, add role="img" and an aria-label.AvatarGroupCount is not interactive. To open the full list of members, put the group in a button or a link.Avatar, AvatarImage and AvatarFallback also accept the props of their Radix UI primitive. The other parts accept the attributes of their element.
| Prop | Type | Default |
|---|---|---|
size | "default" | "sm" | "md" | "lg" | md |
Diameter: | ||
asChild | boolean | - |
| See the element or the Radix UI primitive this part renders. | ||
| Prop | Type | Default |
|---|---|---|
onLoadingStatusChange | ((status: ImageLoadingStatus) => void) | - |
| See the element or the Radix UI primitive this part renders. | ||
asChild | boolean | - |
| See the element or the Radix UI primitive this part renders. | ||
| Prop | Type | Default |
|---|---|---|
delayMs | number | - |
| See the element or the Radix UI primitive this part renders. | ||
asChild | boolean | - |
| See the element or the Radix UI primitive this part renders. | ||
AvatarBadge has no props of its own. It accepts the attributes of the element it renders.
AvatarGroup has no props of its own. It accepts the attributes of the element it renders.
AvatarGroupCount has no props of its own. It accepts the attributes of the element it renders.