Avatar

An image representation of a user or entity with a graceful text fallback.

AL

Installation

Terminal
pnpm dlx @dowel-ui/cli add avatar

npm 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

PropTypeDefault
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

  • Testedpasses
  • axe assertionpasses
  • Keyboard testeddoes not apply
  • Storybook examplespasses
  • Accessibility documentedpasses
  • Semantic tokens onlypasses
  • Motion from tokensdoes not apply
  • className mergedpasses
  • Visible focusdoes not apply
  • No fixed widthspasses

Used in

Whole screens assembled from this component. Installing one brings this and everything else it needs with it.

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 };