Octocat

Avatar

A visual representation of a user that displays initials when an image is unavailable

PB
import {
  Avatar,
  AvatarFallback,
  AvatarImage,
} from '@/components/avatar';

export default function AvatarPreview() {
  return (
    <Avatar>
      <AvatarImage src="https://github.com/pdrbrnd.png" />
      <AvatarFallback>Pedro Brandão</AvatarFallback>
    </Avatar>
  );
}

Source Code

'use client';

import { UserIcon } from '@phosphor-icons/react';
import type { VariantProps } from 'cva';

import { cn, cva } from '@/lib/utils/classnames';

const getInitials = (name: string | undefined) => {
  if (!name) return '';

  if (name.length === 1 || name.length === 2) return name;

  return name
    .split(' ')
    .map((n) => n[0])
    .join('');
};

const avatarStyle = cva({
  base: 'relative flex items-center justify-center overflow-hidden bg-foreground-secondary/10 font-semibold text-foreground/80 shadow-[inset_0_0_0_1px_--alpha(var(--color-foreground)/8%)] backdrop-blur-sm',
  variants: {
    variant: {
      circle: 'rounded-full',
      square: 'rounded-md',
    },
    size: {
      '2xs': 'size-4 text-2xs',
      xs: 'size-6 text-2xs',
      sm: 'size-8 text-xs',
      md: 'size-10 text-sm',
      lg: 'size-12 text-base',
      xl: 'size-14 text-lg',
      '2xl': 'size-16 text-xl',
      '3xl': 'size-20 text-3xl',
    },
  },
});

interface AvatarProps extends React.ComponentPropsWithRef<'div'> {
  size?: VariantProps<typeof avatarStyle>['size'];
  variant?: VariantProps<typeof avatarStyle>['variant'];
}

const Avatar = ({
  className,
  variant = 'circle',
  size = 'md',
  children,
  ...props
}: AvatarProps) => {
  return (
    <div className={cn(avatarStyle({ variant, size }), className)} {...props}>
      {children}
    </div>
  );
};

interface AvatarImageProps extends React.ComponentPropsWithRef<'img'> {
  src: string;
}

const AvatarImage = ({ className, src, ...props }: AvatarImageProps) => {
  return (
    <img
      className={cn('absolute inset-0 z-1 object-cover', className)}
      src={src}
      alt=""
      {...props}
    />
  );
};

interface AvatarFallbackProps extends React.ComponentPropsWithRef<'div'> {
  children?: string;
}

const AvatarFallback = ({
  className,
  children,
  ...props
}: AvatarFallbackProps) => {
  return (
    <div className={cn('opacity-80', className)} {...props}>
      {getInitials(children) || <UserIcon weight="bold" />}
    </div>
  );
};

export { Avatar, AvatarFallback, AvatarImage };

Anatomy


          <Avatar>
  <AvatarImage />
  <AvatarFallback />
</Avatar>
        

API Reference

Avatar

Extends the div element.

Prop Default Type
size "md" "2xs""xs""sm""md""lg""xl""2xl""3xl"
variant "circle" "circle""square"

AvatarImage

Extends the img element.

Prop Default Type
src - string

AvatarFallback

Extends the div element.

Prop Default Type
children - string

Examples

Simple

PB
import {
  Avatar,
  AvatarFallback,
  AvatarImage,
} from '@/components/avatar';

export default function AvatarPreview() {
  return (
    <Avatar>
      <AvatarImage src="https://github.com/pdrbrnd.png" />
      <AvatarFallback>Pedro Brandão</AvatarFallback>
    </Avatar>
  );
}

Fallback

PB
S
PB
import { Avatar, AvatarFallback } from '@/components/avatar';

export default function AvatarFallbackPreview() {
  return (
    <div className="flex flex-wrap gap-2">
      {/* Full name */}
      <Avatar>
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      {/* One word */}
      <Avatar>
        <AvatarFallback>Significa</AvatarFallback>
      </Avatar>
      {/* Initials */}
      <Avatar>
        <AvatarFallback>PB</AvatarFallback>
      </Avatar>
      {/* No fallback */}
      <Avatar>
        <AvatarFallback />
      </Avatar>
    </div>
  );
}

Sizes

PB
PB
PB
PB
PB
PB
PB
PB
import { Avatar, AvatarFallback } from '@/components/avatar';

export default function AvatarSizesPreview() {
  return (
    <div className="flex flex-wrap items-center gap-2">
      <Avatar size="2xs">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      <Avatar size="xs">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      <Avatar size="sm">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      <Avatar size="md">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      <Avatar size="lg">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      <Avatar size="xl">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      <Avatar size="2xl">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
      <Avatar size="3xl">
        <AvatarFallback>Pedro Brandão</AvatarFallback>
      </Avatar>
    </div>
  );
}

Broken Image

PB
import {
  Avatar,
  AvatarFallback,
  AvatarImage,
} from '@/components/avatar';

export default function AvatarBrokenImagePreview() {
  return (
    <Avatar>
      <AvatarImage src="broken-image-url" />
      <AvatarFallback>Pedro Brandão</AvatarFallback>
    </Avatar>
  );
}

On top of media

PB
import { Avatar, AvatarFallback } from '@/components/avatar';

export default function AvatarOnTopOfMediaPreview() {
  return (
    <div
      className="relative size-32 overflow-hidden rounded-lg bg-center bg-cover"
      style={{
        backgroundImage:
          'url(https://images.unsplash.com/photo-1682687220742-aba13b6e50ba?q=80)',
      }}
    >
      <div className="flex h-full items-center justify-center">
        <Avatar>
          <AvatarFallback>Pedro Brandão</AvatarFallback>
        </Avatar>
      </div>
    </div>
  );
}

Custom color

PB
import { Avatar, AvatarFallback } from '@/components/avatar';

export default function AvatarCustomColorPreview() {
  return (
    <Avatar className="bg-emerald-500/20">
      <AvatarFallback>Pedro Brandão</AvatarFallback>
    </Avatar>
  );
}

Previous

Setup

Next

Badge