Avatar
Image or initials avatar in multiple sizes and tints.
Sizes
Four sizes from xs to lg.
XSSMMDLG
function AvatarSizes() {
return (
<div className="flex flex-wrap items-center gap-3">
<Avatar size="xs" initials="XS" />
<Avatar size="sm" initials="SM" />
<Avatar size="md" initials="MD" />
<Avatar size="lg" initials="LG" />
</div>
);
}function AvatarSizes() {
return (
<div className="flex flex-wrap items-center gap-3">
<Avatar size="xs" initials="XS" />
<Avatar size="sm" initials="SM" />
<Avatar size="md" initials="MD" />
<Avatar size="lg" initials="LG" />
</div>
);
}Tints
Initials on each background tint.
NEBLLIPI
function AvatarColors() {
return (
<div className="flex flex-wrap items-center gap-3">
<Avatar color="neutral" initials="NE" />
<Avatar color="blue" initials="BL" />
<Avatar color="lime" initials="LI" />
<Avatar color="pink" initials="PI" />
</div>
);
}function AvatarColors() {
return (
<div className="flex flex-wrap items-center gap-3">
<Avatar color="neutral" initials="NE" />
<Avatar color="blue" initials="BL" />
<Avatar color="lime" initials="LI" />
<Avatar color="pink" initials="PI" />
</div>
);
}Installation
npx shadcn@latest add https://boardcn.dev/r/avatar.jsonnpx shadcn@latest add https://boardcn.dev/r/avatar.jsonBoardCN dependencies
The CLI installs these for you — you do not need to add them yourself.
Source
The file the CLI copies into your project.
import { useEffect, useState, type HTMLAttributes, type Ref } from "react";
import { cx, sortCx } from "@/utils/cx";
type AvatarSize = "xs" | "sm" | "md" | "lg";
type AvatarColor = "neutral" | "blue" | "lime" | "pink";
export interface AvatarProps extends HTMLAttributes<HTMLSpanElement> {
size?: AvatarSize;
color?: AvatarColor;
/** Photo URL. Wins over `initials`. */
src?: string;
alt?: string;
/** Fallback initials, e.g. "M". */
initials?: string;
ref?: Ref<HTMLSpanElement>;
}
const styles = sortCx({
base: "inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full text-center align-middle transition-[width,height,font-size] duration-200 ease",
size: {
xs: "size-5 text-[10px] leading-[15px] font-semibold",
sm: "size-6 text-caption-1-semibold tracking-normal",
md: "size-8 text-headline-semibold",
lg: "size-9 text-[18px] leading-6 font-semibold",
},
color: {
neutral: "bg-avatar-neutral-background text-text-secondary",
blue: "bg-blue-300 text-blue-900",
lime: "bg-lime-200 text-lime-700",
pink: "bg-pink-200 text-pink-500",
},
});
export function Avatar({
size = "md",
color = "neutral",
src,
alt,
initials,
className,
ref,
...props
}: AvatarProps) {
const [imageFailed, setImageFailed] = useState(false);
useEffect(() => {
setImageFailed(false);
}, [src]);
return (
<span
ref={ref}
className={cx(styles.base, styles.size[size], styles.color[color], className)}
{...props}
>
{src && !imageFailed ? (
<img
src={src}
alt={alt ?? ""}
loading="lazy"
decoding="async"
className="size-full object-cover"
onError={() => setImageFailed(true)}
/>
) : (
initials
)}
</span>
);
}import { useEffect, useState, type HTMLAttributes, type Ref } from "react";
import { cx, sortCx } from "@/utils/cx";
type AvatarSize = "xs" | "sm" | "md" | "lg";
type AvatarColor = "neutral" | "blue" | "lime" | "pink";
export interface AvatarProps extends HTMLAttributes<HTMLSpanElement> {
size?: AvatarSize;
color?: AvatarColor;
/** Photo URL. Wins over `initials`. */
src?: string;
alt?: string;
/** Fallback initials, e.g. "M". */
initials?: string;
ref?: Ref<HTMLSpanElement>;
}
const styles = sortCx({
base: "inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full text-center align-middle transition-[width,height,font-size] duration-200 ease",
size: {
xs: "size-5 text-[10px] leading-[15px] font-semibold",
sm: "size-6 text-caption-1-semibold tracking-normal",
md: "size-8 text-headline-semibold",
lg: "size-9 text-[18px] leading-6 font-semibold",
},
color: {
neutral: "bg-avatar-neutral-background text-text-secondary",
blue: "bg-blue-300 text-blue-900",
lime: "bg-lime-200 text-lime-700",
pink: "bg-pink-200 text-pink-500",
},
});
export function Avatar({
size = "md",
color = "neutral",
src,
alt,
initials,
className,
ref,
...props
}: AvatarProps) {
const [imageFailed, setImageFailed] = useState(false);
useEffect(() => {
setImageFailed(false);
}, [src]);
return (
<span
ref={ref}
className={cx(styles.base, styles.size[size], styles.color[color], className)}
{...props}
>
{src && !imageFailed ? (
<img
src={src}
alt={alt ?? ""}
loading="lazy"
decoding="async"
className="size-full object-cover"
onError={() => setImageFailed(true)}
/>
) : (
initials
)}
</span>
);
}Props
Generated from the component's TypeScript types. Standard DOM and React Aria props are omitted.
Avatar
| Prop | Type | Default | Description |
|---|---|---|---|
| alt | string | — | — |
| color | "neutral" | "blue" | "lime" | "pink" | neutral | — |
| initials | string | — | Fallback initials, e.g. "M". |
| size | "xs" | "sm" | "md" | "lg" | md | — |
| src | string | — | Photo URL. Wins over `initials`. |