shadcn.io is not affiliated with official shadcn/ui
Shadcn Avatar for React and Tailwind
Displays a user's profile image with fallback.
VV
CN
VV
SA
PV+2
Installation
bunx --bun shadcn@latest add https://kit.dev/r/avatar.jsonpnpm dlx shadcn@latest add https://kit.dev/r/avatar.jsonnpx shadcn@latest add https://kit.dev/r/avatar.jsonyarn shadcn@latest add https://kit.dev/r/avatar.jsonThis component depends on Status. Install it first if you haven't already.
Install the following dependencies:
bun add @ark-ui/react tailwind-variantspnpm add @ark-ui/react tailwind-variantsnpm install @ark-ui/react tailwind-variantsyarn add @ark-ui/react tailwind-variantsCopy and paste the following code into your project.
"use client";
import {
Avatar as ArkAvatar,
useAvatar as useArkAvatar,
useAvatarContext as useArkAvatarContext,
} from "@ark-ui/react/avatar";
import { ark } from "@ark-ui/react/factory";
import type React from "react";
import { tv, type VariantProps } from "tailwind-variants";
import { cn } from "@/lib/utils";
import {
Status,
type statusVariants,
} from "@/components/ui/status";
export const useAvatar = useArkAvatar;
export const useAvatarContext = useArkAvatarContext;
export const AvatarContext = ArkAvatar.Context;
const avatarVariants = tv({
base: [
"group/avatar",
"relative",
"size-8",
"inline-flex shrink-0 items-center justify-center",
"bg-background",
"select-none font-medium text-xs",
"rounded-full",
"after:absolute after:inset-0 after:rounded-[inherit] after:border after:border-border after:mix-blend-darken dark:after:mix-blend-lighten",
],
variants: {
size: {
sm: "size-6",
md: "size-8",
lg: "size-10",
},
},
defaultVariants: {
size: "md",
},
});
interface AvatarProps
extends React.ComponentProps<typeof ArkAvatar.Root>,
VariantProps<typeof avatarVariants> {}
export const Avatar = (props: AvatarProps) => {
const { size = "md", className, ...rest } = props;
return (
<ArkAvatar.Root
className={cn(avatarVariants({ size }), className)}
data-size={size}
data-slot="avatar"
{...rest}
/>
);
};
export const AvatarRootProvider = (
props: React.ComponentProps<typeof ArkAvatar.RootProvider> &
VariantProps<typeof avatarVariants>
) => {
const { size = "md", className, ...rest } = props;
return (
<ArkAvatar.RootProvider
className={cn(avatarVariants({ size }), className)}
data-size={size}
data-slot="avatar"
{...rest}
/>
);
};
export const AvatarImage = (
props: React.ComponentProps<typeof ArkAvatar.Image>
) => {
const { className, ...rest } = props;
return (
<ArkAvatar.Image
className={cn(
"size-full",
"aspect-square object-cover",
"rounded-[inherit]",
className
)}
data-slot="avatar-image"
{...rest}
/>
);
};
export const AvatarFallback = (
props: React.ComponentProps<typeof ArkAvatar.Fallback>
) => {
const { className, ...rest } = props;
return (
<ArkAvatar.Fallback
className={cn(
"size-full",
"flex items-center justify-center",
"bg-muted",
"rounded-[inherit]",
"[&_svg]:size-4 group-data-[size=lg]/avatar:[&_svg]:size-4.5 group-data-[size=sm]/avatar:[&_svg]:size-3",
className
)}
data-slot="avatar-fallback"
{...rest}
/>
);
};
interface AvatarBadgeProps
extends React.ComponentProps<typeof ark.span>,
Pick<VariantProps<typeof statusVariants>, "variant"> {}
export const AvatarBadge = (props: AvatarBadgeProps) => {
const { variant, className, ...rest } = props;
return (
<Status
className={cn(
"absolute inset-e-0 bottom-0 z-10",
"flex items-center justify-center",
"group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&_svg]:hidden",
"group-data-[size=md]/avatar:size-2.5 group-data-[size=md]/avatar:[&_svg]:size-2",
"group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&_svg]:size-2",
className
)}
data-slot="avatar-badge"
variant={variant}
{...rest}
/>
);
};
export const AvatarGroup = (props: React.ComponentProps<typeof ark.div>) => {
const { className, ...rest } = props;
return (
<ark.div
className={cn(
"flex -space-x-2",
"**:data-[slot=avatar]:ring-2 **:data-[slot=avatar]:ring-background",
className
)}
data-slot="avatar-group"
{...rest}
/>
);
};
export const AvatarGroupCount = (
props: React.ComponentProps<typeof ark.div>
) => {
const { className, ...rest } = props;
return (
<ark.div
className={cn(
"relative",
"size-8",
"flex shrink-0 items-center justify-center",
"bg-muted",
"select-none text-muted-foreground text-sm",
"rounded-full",
"ring-2 ring-background",
"[&_svg]:size-4",
className
)}
data-slot="avatar-group-count"
{...rest}
/>
);
};Update the import paths to match your project setup.
Anatomy
Avatar
├── AvatarImage
└── AvatarFallbackUsage
import {
Avatar,
AvatarBadge,
AvatarFallback,
AvatarGroup,
AvatarGroupCount,
AvatarImage,
} from "@/components/ui/avatar";<div className="flex flex-row flex-wrap items-center gap-6 md:gap-12">
<Avatar>
<AvatarImage alt="@vinihvc" src="https://github.com/vinihvc.png" />
<AvatarFallback>VV</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage alt="@shadcn" src="https://github.com/shadcn.png" />
<AvatarFallback>CN</AvatarFallback>
<AvatarBadge variant="success" />
</Avatar>
<AvatarGroup className="grayscale">
<Avatar>
<AvatarImage alt="@vinihvc" src="https://github.com/vinihvc.png" />
<AvatarFallback>VV</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
alt="@segunadebayo"
src="https://github.com/segunadebayo.png"
/>
<AvatarFallback>SA</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage
alt="@pasqualevitiello"
src="https://github.com/pasqualevitiello.png"
/>
<AvatarFallback>PV</AvatarFallback>
</Avatar>
<AvatarGroupCount>+2</AvatarGroupCount>
</AvatarGroup>
</div>Demos
Badge With Icon
Context
Custom Radius
Events
Fallback Icon
Group
Group Count
Group Count Icon
Group Popover
Hover Card
Root Provider
Size Custom
Size Lg
Size Md
Size Sm
With Status
API Reference
Avatar
div
PropType
AttributeType
AvatarImage
img
PropType
AttributeType
AvatarFallback
span
PropType
AttributeType
AvatarBadge
PropType
AttributeType
AvatarGroup
div
PropType
AttributeType
AvatarGroupCount
div
PropType
AttributeType
AvatarRootProvider
div
PropType
AttributeType
useAvatar
AvatarContext
PropType