Skip to content

Avatar

A circular user avatar with image support and initials fallback in three sizes.

An image, or the initials that stand in for one. Three sizes, all circles, all sized in the same steps the rest of the library uses.

Root class newt-avatar
import { Avatar } from "@/registry/bases/newt/ui/avatar"

export default function AvatarDemo() {
  return (
    <div className="flex items-center gap-4">
      <Avatar>N</Avatar>
      <Avatar size="sm">N</Avatar>
      <Avatar size="lg">N</Avatar>
    </div>
  )
}
<script setup lang="ts">
import { Avatar } from "~~/registry/bases/newt/ui/avatar"
</script>

<template>
  <div class="flex items-center gap-4">
    <Avatar>N</Avatar>
    <Avatar size="sm">N</Avatar>
    <Avatar size="lg">N</Avatar>
  </div>
</template>

Installation

pnpm dlx newtui@latest add avatar
npx newtui@latest add avatar
yarn dlx newtui@latest add avatar
bunx newtui@latest add avatar

Install the dependencies

pnpm dlx --yes class-variance-authority
npx --yes class-variance-authority
yarn dlx --yes class-variance-authority
bunx --yes class-variance-authority

Copy the source into your project

import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react"

import { cn } from "@/lib/utils"

const avatarVariants = cva(
  "relative flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-newt-brand font-semibold text-white",
  {
    variants: {
      size: {
        sm: "h-6 w-6 text-[11px]",
        default: "h-10 w-10 text-base",
        lg: "h-20 w-20 text-[28px]",
      },
    },
    defaultVariants: {
      size: "default",
    },
  }
)

export interface AvatarProps
  extends
    React.HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof avatarVariants> {}

const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
  ({ className, size, ...props }, ref) => (
    <div
      ref={ref}
      className={cn(avatarVariants({ size }), className)}
      {...props}
    />
  )
)
Avatar.displayName = "Avatar"

const AvatarImage = React.forwardRef<
  HTMLImageElement,
  React.ImgHTMLAttributes<HTMLImageElement>
>(({ className, alt = "", ...props }, ref) => (
  <img
    ref={ref}
    alt={alt}
    className={cn("h-full w-full object-cover", className)}
    {...props}
  />
))
AvatarImage.displayName = "AvatarImage"

const AvatarFallback = React.forwardRef<
  HTMLSpanElement,
  React.HTMLAttributes<HTMLSpanElement>
>(({ className, ...props }, ref) => (
  <span
    ref={ref}
    className={cn("flex h-full w-full items-center justify-center", className)}
    {...props}
  />
))
AvatarFallback.displayName = "AvatarFallback"

export { Avatar, AvatarImage, AvatarFallback, avatarVariants }
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

import { avatarVariants, type AvatarVariants } from "."

const props = defineProps<{
  class?: HTMLAttributes["class"]
  size?: AvatarVariants["size"]
}>()
</script>

<template>
  <div :class="cn(avatarVariants({ size: props.size }), props.class)">
    <slot />
  </div>
</template>
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
  src: string
  alt?: string
}>()
</script>

<template>
  <img
    :src="props.src"
    :alt="props.alt ?? ''"
    :class="cn('h-full w-full object-cover', props.class)"
  />
</template>
<script setup lang="ts">
import type { HTMLAttributes } from "vue"

import { cn } from "@/lib/utils"

const props = defineProps<{ class?: HTMLAttributes["class"] }>()
</script>

<template>
  <span
    :class="cn('flex h-full w-full items-center justify-center', props.class)"
  >
    <slot />
  </span>
</template>
import { cva, type VariantProps } from "class-variance-authority"

export { default as Avatar } from "./Avatar.vue"
export { default as AvatarImage } from "./AvatarImage.vue"
export { default as AvatarFallback } from "./AvatarFallback.vue"

export const avatarVariants = cva(
  "relative flex shrink-0 items-center justify-center overflow-hidden rounded-full bg-newt-brand font-semibold text-white",
  {
    variants: {
      size: {
        sm: "h-6 w-6 text-[11px]",
        default: "h-10 w-10 text-base",
        lg: "h-20 w-20 text-[28px]",
      },
    },
    defaultVariants: {
      size: "default",
    },
  }
)

export type AvatarVariants = VariantProps<typeof avatarVariants>

Update the import paths

The files import @/lib/utils and sibling components through the aliases in your components.json. Point them at wherever those live in your project.

Usage

import { Avatar } from "@/components/ui/avatar"

export function Example() {
  return <Avatar />
}
<script setup lang="ts">
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"
</script>

<template>
  <Avatar />
</template>

API reference

Avatar

PropType
size?"sm" | "default" | "lg"

24px, 40px or 80px.

Type"sm" | "default" | "lg"
Default"default"
src?string

Image URL. Falls back to the children when it fails to load.

Typestring
alt?string

Accessible name for the image.

Typestring

Every part also accepts the native attributes of the element it renders, and a className that is merged rather than replaced.

Accessibility

An avatar next to a name is decorative: the name is the accessible name, so alt="" is correct and repeating it is noise. An avatar that stands alone — a stack of participants, an author with no byline — needs a real alt.

Tokens

Avatar reads its colours, radii and motion from the --newt-* tokens installed with the library. Override a token and every component that reads it follows, including this one — see the token layer. In the plain HTML and CSS distribution the same component is newt-avatar.