Avatar

An image element with a fallback for representing the user.

Examples

Basic

PropDefaultTypeDescription
src-stringThe image source.
alt-stringThe alternative text.
label-stringThe placeholder of the avatar when it is loading. By default, it uses the first letters of each word in the alt prop.
Preview
Code
PRPR

Variant

PropDefaultTypeDescription
avatarsoft{variant}The variant of the avatar.
VariantDescription
softThe default variant.
solidThe solid variant.
outlineThe outline variant.
~The unstyle or base variant
Preview
Code
PRPRPRPR

Color

PropDefaultTypeDescription
avatar{variant}-gray{variant}-{color}The color of the avatar.
Preview
Code
Dynamic colors:
PRPRPRPRPRPR
Static colors:
PRPR

Icon

PropDefaultTypeDescription
iconfalsebooleanIf true, the label will be wrapped as an Icon component. The label can be passed as the name of the icon.
Preview
Code

Size and Square

PropDefaultTypeDescription
sizemdstringSets the size of the avatar.
square2.5remstringSets the avatar to a square shape with specified dimensions. This does not affect the size of the fallback value.

🚀 Adjust input size freely using any size, breakpoints (e.g., sm:sm, xs:lg), or states (e.g., hover:lg, focus:3xl).

Preview
Code

Rounded

PropDefaultTypeDescription
roundedfullstringSet the avatar to have rounded corners.
Preview
Code

With Indicator

Preview
Code
PR
PR
11
PRNewNew

Customization

You can customize the avatar using the una prop and utility classes.

Preview
Code
PRPR

Slots

SlotPropsDescription
default-The image element of the avatar.
fallback-The fallback element of the avatar.
Preview
Code
PR

Presets

shortcuts/avatar.ts
type AvatarPrefix = 'avatar'

export const staticAvatar: Record<`${AvatarPrefix}-${string}` | AvatarPrefix, string> = {
  // base
  'avatar': 'relative flex shrink-0 overflow-hidden leading-1.5em',
  'avatar-image': 'aspect-square h-full w-full',
  'avatar-fallback': 'flex h-full w-full items-center justify-center',

  'avatar-label': '',
  'avatar-icon': 'text-1em',

  // variants
  'avatar-solid-white': 'bg-base text-base ring-1 ring-base',
  'avatar-solid-black': 'bg-inverted text-inverted',
}

export const dynamicAvatar: [RegExp, (params: RegExpExecArray) => string][] = [
  // variants
  [/^avatar-solid(-(\S+))?$/, ([, , c = 'gray']) => `bg-${c}-600 dark:bg-${c}-500 text-inverted`],
  [/^avatar-soft(-(\S+))?$/, ([, , c = 'gray']) => `bg-${c}-50 text-${c}-700 dark:text-${c}-400 dark:bg-${c}-900`],
  [/^avatar-outline(-(\S+))?$/, ([, , c = 'gray']) => `bg-transparent text-${c}-500 dark:text-${c}-400 ring-1 ring-${c}-500 dark:ring-${c}-400`],
]

export const avatar = [
  ...dynamicAvatar,
  staticAvatar,
]

Props

types/avatar.ts
import type { AvatarFallbackProps, AvatarImageProps, AvatarRootProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'

interface BaseProps {
  class?: HTMLAttributes['class']
  /**
   * Set the size of the avatar.
   */
  size?: HTMLAttributes['class']
  /**
   * Set the height and width of the avatar.
   */
  square?: HTMLAttributes['class']
  /**
   * Set the border radius of the avatar.
   */
  rounded?: HTMLAttributes['class']
}

export interface NAvatarProps extends BaseProps, NAvatarRootProps, NAvatarAvatarFallbackProps, NAvatarImageProps {
  _avatarRoot?: NAvatarRootProps
  _avatarImage?: NAvatarImageProps
  _avatarFallback?: NAvatarAvatarFallbackProps
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/avatar.ts
   */
  una?: NAvatarUnaProps
}

export interface NAvatarRootProps extends AvatarRootProps, BaseProps {
  /**
   * Allows you to add `UnaUI` avatar preset properties,
   * Think of it as a shortcut for adding options or variants to the preset if available.
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/avatar.ts
   * @example
   * avatar="solid-green"
   */
  avatar?: HTMLAttributes['class']

  una?: NAvatarUnaProps['avatarRoot']
}

export interface NAvatarAvatarFallbackProps extends AvatarFallbackProps, BaseProps {
  /**
   * Add a label to the fallback.
   */
  label?: string
  /**
   * Convert `label` prop to icon component.
   *
   * @default false
   * @example
   * icon
   * label="i-lucide-user"
   */
  icon?: boolean

  una?: NAvatarUnaProps['avatarFallback']
}

export interface NAvatarImageProps extends Omit<AvatarImageProps, 'src'>, BaseProps {
  src?: string
  alt?: string
  una?: NAvatarUnaProps['avatarImage']
}

export interface NAvatarUnaProps {
  avatarRoot?: HTMLAttributes['class']
  avatarImage?: HTMLAttributes['class']
  avatarFallback?: HTMLAttributes['class']

  avatarLabel?: HTMLAttributes['class']
  avatarIcon?: HTMLAttributes['class']
}

Components

Avatar.vue
AvatarFallback.vue
AvatarImage.vue
<script setup lang="ts">
import type { NAvatarProps } from '../../../types'
import { AvatarRoot } from 'radix-vue'
import { cn } from '../../../utils'
import AvatarFallback from './AvatarFallback.vue'
import AvatarImage from './AvatarImage.vue'

defineOptions({
  inheritAttrs: false,
})

const props = withDefaults(defineProps<NAvatarProps>(), {
  as: 'span',
  size: 'md',
  rounded: 'full',
  square: '2.5em',
  avatar: 'soft',
})
</script>

<template>
  <AvatarRoot
    as-child
  >
    <component
      :is="as"
      :class="cn(
        'avatar',
        una?.avatarRoot,
        props.class,
      )"
      :size
      :rounded
      :square
      :avatar
      v-bind="{ ..._avatarRoot, ...$attrs }"
    >
      <slot :props>
        <AvatarImage
          v-if="src"
          :src
          :una
          v-bind="_avatarImage"
        />
      </slot>

      <AvatarFallback
        :avatar
        :label="label || alt?.split(' ').map(word => word[0]).join('').slice(0, 2)"
        :icon
        v-bind="_avatarFallback"
        :una
      >
        <slot name="fallback" />
      </AvatarFallback>
    </component>
  </AvatarRoot>
</template>