Avatar

A round portrait standing for a person or an entity.

Shion Hoshimi

Shion Hoshimi

Translated 128 light novels

<script setup lang="ts">
  import { Avatar, Card, Inline, Stack, Text } from '@hina-ui/vue'
</script>

<template>
  <Card class="w-full max-w-sm">
    <Inline gap="sm">
      <Avatar size="lg" src="/avatars/selfie.webp" name="Shion Hoshimi" />
      <Stack gap="none">
        <Text class="font-medium">Shion Hoshimi</Text>
        <Text tone="muted" size="sm">Translated 128 light novels</Text>
      </Stack>
    </Inline>
  </Card>
</template>
vue

Usage

import { Avatar } from '@hina-ui/vue'
ts

src is the picture and name is the person behind it. The picture shows once it loads; failing that, the initials of the name; failing that, a generic icon.

Shion HoshimiSH
<script setup lang="ts">
  import { Avatar, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline>
    <Avatar src="/avatars/paper.webp" alt="Shion Hoshimi" />
    <Avatar name="Shion Hoshimi" />
    <Avatar />
  </Inline>
</template>
vue

Examples

Sizes

The three steps are 24, 32 and 40 pixels. An avatar is always round; there is no square or rounded-corner option.

Shion HoshimiShion HoshimiShion Hoshimi
<script setup lang="ts">
  import { Avatar, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline align="center">
    <Avatar size="sm" src="/avatars/peek.webp" alt="Shion Hoshimi" />
    <Avatar size="md" src="/avatars/peek.webp" alt="Shion Hoshimi" />
    <Avatar size="lg" src="/avatars/peek.webp" alt="Shion Hoshimi" />
  </Inline>
</template>
vue

Fallbacks

Initials follow the writing system: a Chinese, Japanese or Korean name gives its first character, a Western one the initials of its first two parts. A picture that fails to load falls back the same way, and the broken image never shows.

SH

Two initials

星

One character for CJK

An icon without a name

Shion Hoshimi

The image failed to load

<script setup lang="ts">
  import { Avatar, Inline, Stack, Text } from '@hina-ui/vue'
</script>

<template>
  <Inline align="start" class="gap-8">
    <Stack gap="xs" align="center">
      <Avatar name="Shion Hoshimi" />
      <Text tone="muted" size="sm">Two initials</Text>
    </Stack>
    <Stack gap="xs" align="center">
      <Avatar name="星见书音" />
      <Text tone="muted" size="sm">One character for CJK</Text>
    </Stack>
    <Stack gap="xs" align="center">
      <Avatar />
      <Text tone="muted" size="sm">An icon without a name</Text>
    </Stack>
    <Stack gap="xs" align="center">
      <Avatar src="/missing.png" name="Shion Hoshimi" />
      <Text tone="muted" size="sm">The image failed to load</Text>
    </Stack>
  </Inline>
</template>
vue

Groups

AvatarGroup stacks several avatars together. max caps how many are shown and folds the rest into a +N. A size on the group sets the size for all of them, and an avatar with its own size keeps it.

All of them

HuhGlassPeekShion Hoshimi

Three at most, the rest folded into a count

+3GlassPeekShion Hoshimi
<script setup lang="ts">
  import { Avatar, AvatarGroup, Stack, Text } from '@hina-ui/vue'

  const members = [
    { src: '/avatars/paper.webp', name: 'Shion Hoshimi' },
    { src: '/avatars/peek.webp', name: 'Peek' },
    { src: '/avatars/glass.webp', name: 'Glass' },
    { src: '/avatars/huh.webp', name: 'Huh' },
    { src: '/avatars/run.webp', name: 'Run' },
    { src: '/avatars/sleep.webp', name: 'Sleep' },
  ]
</script>

<template>
  <Stack>
    <Stack gap="xs">
      <Text tone="muted" size="sm">All of them</Text>
      <AvatarGroup>
        <Avatar v-for="m in members.slice(0, 4)" :key="m.name" :src="m.src" :alt="m.name" />
      </AvatarGroup>
    </Stack>
    <Stack gap="xs">
      <Text tone="muted" size="sm">Three at most, the rest folded into a count</Text>
      <AvatarGroup :max="3" size="lg">
        <Avatar v-for="m in members" :key="m.name" :src="m.src" :alt="m.name" />
      </AvatarGroup>
    </Stack>
  </Stack>
</template>
vue

Overlap spacing and separator rings apply directly to the group’s outer child elements. A custom avatar wrapped in a trigger does not need to forward group layout classes to its inner avatar. The wrapper’s rounding and decoration remain under the custom component’s control.

Custom children can import useAvatarGroup from the package root to read the group size reactively. It returns null outside a group. For example, preserve an individual avatar’s size override in a custom component:

import { computed } from 'vue'
import { useAvatarGroup, type AvatarVariants } from '@hina-ui/vue'

const props = defineProps<{ size?: AvatarVariants['size'] }>()
const group = useAvatarGroup()
const size = computed(() => props.size ?? group?.value.size ?? 'md')
ts

max counts entries supplied by the default slot, including a v-for directly in that slot. Multiple avatars rendered inside a custom component are not counted separately; supply one avatar per slot entry when an accurate +N is required.

Custom content

The default slot replaces the built-in fallback with an icon or a short piece of text.

★
<script setup lang="ts">
  import { Bot } from '@lucide/vue'
  import { Avatar, Inline } from '@hina-ui/vue'
</script>

<template>
  <Inline>
    <Avatar>
      <Bot />
    </Avatar>
    <Avatar>★</Avatar>
  </Inline>
</template>
vue

Behaviour

  • The avatar is rendered by Image, so its address goes through provideImageResolver too and a skeleton holds the circle while it loads.
  • The picture fills the circle with object-fit: cover, so an image of a different aspect ratio is not stretched.
  • The fallback shows when there is no src or the picture fails; a failed picture is removed.
  • Image’s other props can be written straight on Avatar — fallback, lazy, eager and the rest are passed through.

Accessibility

  • With a picture, alt is its alternative text; without alt it falls back to name.
  • The initials and the icon are decorative: a screen reader reads the name in the surrounding text rather than announcing the avatar twice.

API

Prop
Type
Default
Description
src
string
—
The picture
alt
string
—
Alternative text; falls back to name
name
string
—
The name the initials come from
size
'sm' | 'md' | 'lg'
'md'
Size
class
string
—
Classes appended to the root
Slot
Description
default
Replaces the built-in fallback

AvatarGroup

Prop
Type
Default
Description
max
number
—
How many to show; the rest fold into a count
size
'sm' | 'md' | 'lg'
—
Size for the group; an avatar may override it
class
string
—
Classes appended to the container
Slot
Description
default
The avatars

useAvatarGroup

useAvatarGroup() returns ComputedRef<AvatarGroupContext> | null. AvatarGroupContext is also exported from the package root.

Field
Type
Description
size
AvatarVariants['size']
The nearest group’s size, or undefined if the group leaves it unset