UI/UI
Avatar
An image element with a fallback for representing the user.
PSVCJD
<div className="flex gap-4 flex-wrap items-center">
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="https://github.com/fuma-nama.png" alt="@fuma-nama" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>JD</AvatarFallback>
</Avatar>
</div>
Installation
Install following dependencies:
npm install pnpm add @radix-ui/react-avatar class-variance-authority
pnpm add pnpm add @radix-ui/react-avatar class-variance-authority
yarn add pnpm add @radix-ui/react-avatar class-variance-authority
bun add pnpm add @radix-ui/react-avatar class-variance-authority
Required Component
This component requires the Tooltip
component when using
the tooltip functionality. Make sure you have installed and set up the
Tooltip component before using tooltips with avatars.
Copy and paste the following code into your project.
"use client";
import * as React from "react";
import * as AvatarPrimitive from "@radix-ui/react-avatar";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "./Tooltip";
const avatarVariants = cva(
"relative flex shrink-0 overflow-hidden rounded-full",
{
variants: {
size: {
xs: "h-6 w-6",
sm: "h-8 w-8",
md: "h-10 w-10",
lg: "h-12 w-12",
xl: "h-16 w-16",
"2xl": "h-20 w-20",
},
},
defaultVariants: {
size: "md",
},
},
);
interface AvatarProps
extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>,
VariantProps<typeof avatarVariants> {
tooltip?: string | React.ComponentProps<typeof TooltipContent>;
}
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
AvatarProps
>(({ className, size, tooltip, ...props }, ref) => {
const avatar = (
<AvatarPrimitive.Root
ref={ref}
className={cn(avatarVariants({ size }), className)}
{...props}
/>
);
if (!tooltip) {
return avatar;
}
const tooltipProps =
typeof tooltip === "string" ? { children: tooltip } : tooltip;
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>{avatar}</TooltipTrigger>
<TooltipContent {...tooltipProps} />
</Tooltip>
</TooltipProvider>
);
});
Avatar.displayName = AvatarPrimitive.Root.displayName;
const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full object-cover", className)}
{...props}
/>
));
AvatarImage.displayName = AvatarPrimitive.Image.displayName;
const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-[hsl(var(--hu-muted))] text-[hsl(var(--hu-muted-foreground))] font-medium",
className,
)}
{...props}
/>
));
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName;
interface AvatarGroupProps extends React.HTMLAttributes<HTMLDivElement> {
max?: number;
spacing?: "tight" | "normal" | "loose";
size?: VariantProps<typeof avatarVariants>["size"];
children: React.ReactElement[];
}
const avatarGroupSpacing = {
tight: "-space-x-2",
normal: "-space-x-1",
loose: "space-x-1",
};
const AvatarGroup = React.forwardRef<HTMLDivElement, AvatarGroupProps>(
(
{ className, max = 3, spacing = "normal", size = "md", children, ...props },
ref,
) => {
const avatarsToShow = children.slice(0, max);
const remainingCount = Math.max(0, children.length - max);
return (
<div
ref={ref}
className={cn(
"flex items-center",
avatarGroupSpacing[spacing],
className,
)}
{...props}
>
{avatarsToShow.map((child, index) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, {
key: index,
size,
className: cn(
"border-2 border-[hsl(var(--hu-background))]",
(child.props as any)?.className,
),
} as any);
}
return child;
})}
{remainingCount > 0 && (
<Avatar
size={size}
className="border-2 border-[hsl(var(--hu-background))]"
>
<AvatarFallback className="bg-[hsl(var(--hu-secondary))] text-[hsl(var(--hu-secondary-foreground))] font-semibold">
+{remainingCount}
</AvatarFallback>
</Avatar>
)}
</div>
);
},
);
AvatarGroup.displayName = "AvatarGroup";
export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, avatarVariants };
export type { AvatarGroupProps };
npx hextaui@latest add avatar
pnpm dlx hextaui@latest add avatar
yarn dlx hextaui@latest add avatar
bun x hextaui@latest add avatar
Usage
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/Avatar";
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
Examples
Default
PS
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
Sizes
PSPSPSPSPSPS
<div className="flex gap-4 flex-wrap items-center">
<Avatar size="xs">
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar size="sm">
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar size="md">
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar size="lg">
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar size="xl">
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar size="2xl">
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
</div>
Fallback Only
PSJDVC
<div className="flex gap-4 flex-wrap items-center">
<Avatar>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>VC</AvatarFallback>
</Avatar>
</div>
Avatar Group
Default Group (max 3)
PSVCJD+2
Large Group (max 5)
PSVCJDABXY+2
<div className="flex flex-col gap-6">
<div className="space-y-2">
<h4 className="text-sm font-medium">Default Group (max 3)</h4>
<AvatarGroup>
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="https://github.com/fuma-nama.png" alt="@fuma-nama" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>AB</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>XY</AvatarFallback>
</Avatar>
</AvatarGroup>
</div>
<div className="space-y-2">
<h4 className="text-sm font-medium">Large Group (max 5)</h4>
<AvatarGroup max={5} size="lg">
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="https://github.com/fuma-nama.png" alt="@fuma-nama" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>AB</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>XY</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>MN</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>QR</AvatarFallback>
</Avatar>
</AvatarGroup>
</div>
</div>
Group Spacing
Tight Spacing
PSVCJD
Normal Spacing
PSVCJD
Loose Spacing
PSVCJD
<div className="flex flex-col gap-6">
<div className="space-y-2">
<h4 className="text-sm font-medium">Tight Spacing</h4>
<AvatarGroup spacing="tight">
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="https://github.com/fuma-nama.png" alt="@fuma-nama" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>JD</AvatarFallback>
</Avatar>
</AvatarGroup>
</div>
<div className="space-y-2">
<h4 className="text-sm font-medium">Normal Spacing</h4>
<AvatarGroup spacing="normal">
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="https://github.com/fuma-nama.png" alt="@fuma-nama" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>JD</AvatarFallback>
</Avatar>
</AvatarGroup>
</div>
<div className="space-y-2">
<h4 className="text-sm font-medium">Loose Spacing</h4>
<AvatarGroup spacing="loose">
<Avatar>
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar>
<AvatarImage src="https://github.com/fuma-nama.png" alt="@fuma-nama" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<Avatar>
<AvatarFallback>JD</AvatarFallback>
</Avatar>
</AvatarGroup>
</div>
</div>
Avatar with Tooltip
Note: The Tooltip component is required to use the tooltip functionality with Avatar.
PSVCJD+1
<div className="flex gap-4 flex-wrap items-center">
<Avatar tooltip="preetsuthar17">
<AvatarImage
src="https://github.com/preetsuthar17.png"
alt="@preetsuthar17"
/>
<AvatarFallback>PS</AvatarFallback>
</Avatar>
<Avatar tooltip={{ children: "fuma-nama", variant: "dark" }}>
<AvatarImage src="https://github.com/fuma-nama.png" alt="@fuma-nama" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<Avatar tooltip="John Doe" size="lg">
<AvatarFallback>JD</AvatarFallback>
</Avatar>
<Avatar
tooltip={{ children: "Admin User", variant: "destructive" }}
size="sm"
>
<AvatarFallback>AU</AvatarFallback>
</Avatar>
</div>
Props
Avatar
Prop | Type | Default |
---|---|---|
className? | string | undefined |
tooltip? | string | TooltipContentProps | undefined |
size? | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "md" |
AvatarGroup
Prop | Type | Default |
---|---|---|
className? | string | undefined |
children? | React.ReactElement[] | required |
size? | "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "md" |
spacing? | "tight" | "normal" | "loose" | "normal" |
max? | number | 3 |
Edit on GitHub
Last updated on