Avatar
An image representation of a user or entity with a graceful text fallback.
AL
Installation
Terminal
pnpm dlx @dowel-ui/cli add avatarnpm packages installed: class-variance-authority, radix-ui.
Accessibility
Give AvatarImage a meaningful alt, or alt="" when the adjacent text already names the person. Fallback initials are decorative and are not announced separately.
Props
Avatar
| Prop | Type | Default |
|---|---|---|
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" |
Every prop of Radix UI’s Avatar.Root, plus className.
AvatarImage
Every prop of Radix UI’s Avatar.Image, plus className.
AvatarFallback
Every prop of Radix UI’s Avatar.Fallback, plus className.
Quality
7/7 checks, measured from the source and its tests
- Tested — passes
- axe assertion — passes
- Keyboard tested — does not apply
- Storybook examples — passes
- Accessibility documented — passes
- Semantic tokens only — passes
- Motion from tokens — does not apply
- className merged — passes
- Visible focus — does not apply
- No fixed widths — passes
Used in
Whole screens assembled from this component. Installing one brings this and everything else it needs with it.
- Admin — users
- Admin dashboard
- CRM
- Settings
- Team carousel
- Team grid
- Testimonial Rotator
- Testimonial Spotlight
- Testimonial Star Grid
Source
This is exactly what dowel add avatar writes into your project, with imports rewritten to your own path alias.
ui/avatar.tsx
import { cva, type VariantProps } from "class-variance-authority";
import { Avatar as AvatarPrimitive } from "radix-ui";
import type { ComponentPropsWithRef } from "react";
import { cn } from "@/lib/utils";
const avatarVariants = cva(
"relative flex shrink-0 overflow-hidden rounded-full bg-muted select-none",
{
variants: {
size: {
xs: "size-6 text-2xs",
sm: "size-8 text-xs",
md: "size-10 text-sm",
lg: "size-12 text-base",
xl: "size-16 text-lg",
},
},
defaultVariants: {
size: "md",
},
},
);
export interface AvatarProps
extends
ComponentPropsWithRef<typeof AvatarPrimitive.Root>,
VariantProps<typeof avatarVariants> {}
/** Image representation of a user or entity, with a text fallback. */
export function Avatar({ className, size, ...props }: AvatarProps) {
return (
<AvatarPrimitive.Root className={cn(avatarVariants({ size }), className)} {...props} />
);
}
export type AvatarImageProps = ComponentPropsWithRef<typeof AvatarPrimitive.Image>;
export function AvatarImage({ className, ...props }: AvatarImageProps) {
return (
<AvatarPrimitive.Image
className={cn("aspect-square size-full object-cover", className)}
{...props}
/>
);
}
export type AvatarFallbackProps = ComponentPropsWithRef<typeof AvatarPrimitive.Fallback>;
/**
* Shown while the image loads and if it fails.
*
* Radix only renders this once the image has actually errored or is still
* pending, so there is never a flash of initials over a cached image.
*/
export function AvatarFallback({ className, ...props }: AvatarFallbackProps) {
return (
<AvatarPrimitive.Fallback
className={cn(
"flex size-full items-center justify-center bg-muted font-medium text-muted-foreground",
className,
)}
{...props}
/>
);
}
export { avatarVariants };