Demos
How to import
<script setup lang="ts">
import { Avatar, AvatarGroup } from '@fibrous/semi-ui-vue';
</script>
Size
You can change the size of the avatars with size property. The following sizes are supported: extra-extra-small, extra-small,small, default, medium, large, extra-large.
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
const sizes = ['extra-extra-small', 'extra-small', 'small', 'default', 'medium', 'large', 'extra-large'];
</script>
<template>
<div>
<Avatar v-for="size in sizes" :key="size" alt="用户" :size="size" :style="{ margin: '4px' }">U</Avatar>
</div>
</template>Color
Avatars support 16 colors including white, amber, blue, cyan, green, grey, indigo, light-blue, light-green, lime, orange, pink, purple, red, teal, violet, and yellow. You can also use the style prop to customize styles. The default color isgrey.
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
</script>
<template>
<div>
<Avatar alt="Alice Swift" :style="{ margin: '4px' }">AS</Avatar>
<Avatar alt="Bob Matteo" color="red" :style="{ margin: '4px' }">BM</Avatar>
<Avatar alt="Taylor Joy" color="light-blue" :style="{ margin: '4px' }">TJ</Avatar>
<Avatar alt="Zank Lance" :style="{ color: '#f56a00', backgroundColor: '#fde3cf', margin: '4px' }">ZL</Avatar>
<Avatar alt="Youself Zhang" :style="{ backgroundColor: '#87d068', margin: '4px' }">YZ</Avatar>
</div>
</template>Adaptive character size
For the avatar of the character type, the font size will be adjusted adaptively according to the width of the avatar. Use gap to adjust the pixel size on the left and right sides of the character avatar distance.
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
</script>
<template>
<div>
<Avatar :style="{ margin: '4px' }">AS</Avatar>
<Avatar :gap="4" :style="{ margin: '4px' }">Semi</Avatar>
<Avatar :gap="10" :style="{ margin: '4px' }">Semi</Avatar>
</div>
</template>Image
Image avatars can be created by using the src or srcSet prop.
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
const src = '/assets/placeholder/avatar-a.svg';
</script>
<template>
<div>
<Avatar alt="漂亮的猫咪" :src="src" :style="{ margin: '4px' }" />
<Avatar alt="可爱的猫咪" size="small" :src="src" :style="{ margin: '4px' }" />
</div>
</template>Shape
Avatars support two shapes: circle and square. The shape is default to circle.
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
</script>
<template>
<div>
<Avatar alt="用户" :style="{ margin: '4px' }">U</Avatar>
<Avatar alt="用户" shape="square" :style="{ margin: '4px' }">U</Avatar>
</div>
</template>Event
Avatars emit @click, @mouseEnter and @mouseLeave. Supply hover overlay content through the #hoverMask slot. The overlay has no default style.
Code
<script setup lang="ts">
import { IconCamera } from '@fibrous/semi-icons-vue';
import { Avatar } from '@fibrous/semi-ui-vue';
</script>
<template>
<Avatar alt="Bob Downton" color="red">
BD
<template #hoverMask>
<div
:style="{
backgroundColor: 'var(--semi-color-overlay-bg)',
height: '100%',
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}"
>
<IconCamera />
</div>
</template>
</Avatar>
</template>Top and Bottom Slot
Use the topSlot and bottomSlot props to configure badge appearance, and #topSlotText and #bottomSlotText for badge content. The #topSlot and #bottomSlot slots replace the entire badge.
Code
<script setup lang="ts">
import { IconPlus } from '@fibrous/semi-icons-vue';
import { Avatar } from '@fibrous/semi-ui-vue';
</script>
<template>
<Avatar alt="漂亮的猫咪" :border="{ color: '#FE2C55', motion: true }" :bottomSlot="{ shape: 'circle', bgColor: '#FE2C55' }" contentMotion size="large" src="/assets/placeholder/avatar-a.svg" :style="{ margin: '4px' }" :topSlot="{ gradientStart: 'rgb(255,23,100)', gradientEnd: 'rgb(237,52,148)' }">
<template #topSlotText>直播</template>
<template #bottomSlotText>
<IconPlus />
</template>
</Avatar>
</template>Top
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
const sizes = ['medium', 'large', 'extra-large'];
</script>
<template>
<div>
<Avatar v-for="size in sizes" :key="size" color="amber" :size="size" :topSlot="{ gradientStart: 'rgb(255,23,100)', gradientEnd: 'rgb(237,52,148)' }">
T
<template #topSlotText>直播</template>
</Avatar>
</div>
</template>Bottom
T
Code
<script setup lang="ts">
import { IconPlus } from '@fibrous/semi-icons-vue';
import { Avatar } from '@fibrous/semi-ui-vue';
const sizes = ['medium', 'large', 'extra-large'];
</script>
<template>
<div>
<Avatar v-for="size in sizes" :key="size" :bottomSlot="{ shape: 'square', bgColor: '#FE2C55' }" color="amber" :size="size">
T
<template #bottomSlotText>直播中</template>
</Avatar>
<br /><br /><br />
<Avatar v-for="size in sizes" :key="`plus-${size}`" :bottomSlot="{ shape: 'circle', bgColor: '#FE2C55' }" color="amber" :size="size">
T
<template #bottomSlotText>
<IconPlus />
</template>
</Avatar>
</div>
</template>Additional border
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
</script>
<template>
<div><Avatar v-for="index in 3" :key="index" border color="amber" :style="{ marginRight: '8px' }">T</Avatar></div>
</template>Additional Animation
Enable additional border and content animation through the motion field of border and the contentMotion prop.
Code
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
const sizes = ['medium', 'large', 'extra-large'];
</script>
<template>
<div>
<Avatar v-for="size in sizes" :key="size" :border="{ motion: true }" color="amber" contentMotion :size="size" :style="{ marginRight: '8px' }">T</Avatar>
</div>
</template>AvatarGroup
You can use AvatarGroup component to display avatars as a group.
Code
<script setup lang="ts">
import { Avatar, AvatarGroup } from '@fibrous/semi-ui-vue';
</script>
<template>
<div>
<AvatarGroup>
<Avatar alt="Lisa LeBlanc" color="red">LL</Avatar>
<Avatar alt="Caroline Xiao">CX</Avatar>
<Avatar alt="Rafal Matin" color="amber">RM</Avatar>
<Avatar alt="Zank Lance" :style="{ color: '#f56a00', backgroundColor: '#fde3cf' }">ZL</Avatar>
<Avatar alt="Youself Zhang" :style="{ backgroundColor: '#87d068' }">YZ</Avatar>
</AvatarGroup>
</div>
</template>You can set the number of avatars to display with maxCount property.
Code
<script setup lang="ts">
import { Avatar, AvatarGroup } from '@fibrous/semi-ui-vue';
</script>
<template>
<div>
<AvatarGroup :maxCount="3">
<Avatar alt="Lisa LeBlanc" color="red">LL</Avatar>
<Avatar alt="Caroline Xiao">CX</Avatar>
<Avatar alt="Rafal Matin" color="amber">RM</Avatar>
<Avatar alt="Zank Lance" :style="{ color: '#f56a00', backgroundColor: '#fde3cf' }">ZL</Avatar>
<Avatar alt="Youself Zhang" :style="{ backgroundColor: '#87d068' }">YZ</Avatar>
</AvatarGroup>
</div>
</template>Customize the more label with the #more="{ restNumber, restAvatars }" scoped slot.
Code
<script setup lang="ts">
import { cloneVNode, type VNode } from 'vue';
import { Avatar, AvatarGroup, Popover } from '@fibrous/semi-ui-vue';
// The group provides existing slot vnodes; cloning preserves their content while overriding the popup size.
function SmallAvatar({ avatar }: { avatar: VNode }) {
return cloneVNode(avatar, { size: 'extra-small' });
}
</script>
<template>
<AvatarGroup :maxCount="3">
<Avatar alt="Lisa LeBlanc" color="red">LL</Avatar>
<Avatar alt="Caroline Xiao">CX</Avatar>
<Avatar alt="Rafal Matin" color="amber">RM</Avatar>
<Avatar alt="Zank Lance" :style="{ color: '#f56a00', backgroundColor: '#fde3cf' }">ZL</Avatar>
<Avatar alt="Youself Zhang" :style="{ backgroundColor: '#87d068' }">YZ</Avatar>
<template #more="{ restNumber, restAvatars }">
<Popover :autoAdjustOverflow="false" position="bottomRight" :style="{ padding: '12px 8px', paddingBottom: 0 }">
<Avatar>{{ `+${restNumber}` }}</Avatar>
<template #content>
<div v-for="(avatar, index) in restAvatars" :key="index" :style="{ paddingBottom: '12px' }">
<SmallAvatar :avatar="avatar" />
<span :style="{ marginLeft: '8px', fontSize: '14px' }">这是段文字描述</span>
</div>
</template>
</Popover>
</template>
</AvatarGroup>
</template>You can set the coverage direction of the avatars with overlapFrom. It has two optional values A and B. The default value is start.
Code
<script setup lang="ts">
import { Avatar, AvatarGroup } from '@fibrous/semi-ui-vue';
const directions = ['start', 'end'] as const;
</script>
<template>
<div>
<div v-for="direction in directions" :key="direction">
<AvatarGroup :overlapFrom="direction">
<Avatar alt="Lisa LeBlanc" color="red">LL</Avatar>
<Avatar alt="Caroline Xiao">CX</Avatar>
<Avatar alt="Rafal Matin" color="amber">RM</Avatar>
<Avatar alt="Zank Lance" :style="{ color: '#f56a00', backgroundColor: '#fde3cf' }">ZL</Avatar>
<Avatar alt="Youself Zhang" :style="{ backgroundColor: '#87d068' }">YZ</Avatar>
</AvatarGroup>
</div>
</div>
</template>API Reference
Avatar
Props
| Property | Description | Type | Default |
|---|---|---|---|
| color | Preset background color of the avatar. | AvatarColor | semiDefault("Avatar", "color", "grey") |
| shape | Avatar shape: circle or square. | AvatarShape | undefined |
| size | Avatar size, as a preset name or a valid CSS size. | string | undefined |
| src | Image source URL. | string | semiGlobalDefault("Avatar", "src") |
| srcSet | Responsive image sources. | string | semiGlobalDefault("Avatar", "srcSet") |
| alt | Alternative text for the avatar image or text. | string | semiGlobalDefault("Avatar", "alt") |
| gap | Space in pixels between the text and either side of the avatar. | number | semiDefault("Avatar", "gap", 3) |
| imgAttr | Native attributes applied to the inner img element. | ImgHTMLAttributes | semiGlobalDefault("Avatar", "imgAttr") |
| topSlot | Gradient, text color, class and style of the top badge; use the topSlotText slot for its content. | AvatarTopSlot | semiGlobalDefault("Avatar", "topSlot") |
| bottomSlot | Shape, background color, text color, class and style of the bottom badge; use the bottomSlotText slot for its content. | AvatarBottomSlot | semiGlobalDefault("Avatar", "bottomSlot") |
| border | Additional border, with optional color and animation. | Typeboolean | { color?: string | undefined; motion?: boolean | undefined; } | semiGlobalDefault("Avatar", "border") |
| contentMotion | Enables animation in the avatar content area. | boolean | semiGlobalDefault("Avatar", "contentMotion") |
| onError | Called when the image fails to load. Return false to prevent the default fallback; this remains a function prop so its result can be read. | Type(() => boolean | void) | undefined |
Events
| Event | Description | Callback parameters |
|---|---|---|
| mouseEnter | Emitted when the pointer enters the avatar. | [event: MouseEvent] |
| mouseLeave | Emitted when the pointer leaves the avatar. | [event: MouseEvent] |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| default | Avatar text or custom content. | any |
| hoverMask | Overlay shown on hover, with styles supplied by the caller. | any |
| topSlot | Replaces the entire top badge. | any |
| bottomSlot | Replaces the entire bottom badge. | any |
| topSlotText | Text or nodes inside the preset top badge. | any |
| bottomSlotText | Text or nodes inside the preset bottom badge. | any |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
class, style and native attributes are passed through attrs. A clickable avatar applies tabindex and aria-* to its single inner focus target.
AvatarGroup
Props
| Property | Description | Type | Default |
|---|---|---|---|
| shape | Shape of the avatars in the group. | AvatarShape | semiDefault("AvatarGroup", "shape", "circle") |
| size | Size of the avatars in the group. | string | semiDefault("AvatarGroup", "size", "medium") |
| overlapFrom | Avatar overlap direction: start or end. | AvatarGroupOverlapFrom | semiDefault("AvatarGroup", "overlapFrom", "start") |
| maxCount | Maximum number of visible avatars; overflow is shown as +N. | number | semiGlobalDefault("AvatarGroup", "maxCount") |
Events
| Event | Description | Callback parameters |
|---|---|---|
| None |
Slots
| Slot | Description | Scope parameters |
|---|---|---|
| default | Avatar components in the group. | any |
| more | Custom overflow label, receiving the remaining count restNumber and the avatar VNode array restAvatars. | Type{ restNumber: number; restAvatars: VNode<RendererNode, RendererElement, { [key: string]: any; }>[]; } |
Exposes
| Name | Description | Type |
|---|---|---|
| None |
Attrs such as class, style and aria-* are applied to the group root, not to the avatars inside it.
Accessibility
- Avatars are generally not used for operations and do not need to be focused. But when the Avatar can be clicked (such as the avatar on the Semi official website), it needs to be focused and respond to the keyboard
EnterandSpaceevents. - A clickable Avatar with an image or text has a single Tab stop, the image or the text label. Its focus order and
aria-*attributes, including those injected by Tooltip, are applied to that element. - When Avatar is used in combination with other components, also check the accessibility guidelines for that component.
- Avatar's
altattribute can be read by screen readers, when using the avatar component, please use thealtattribute to explain the content of the image.
<script setup lang="ts">
import { Avatar } from '@fibrous/semi-ui-vue';
const src = '/assets/placeholder/avatar-a.svg';
</script>
<template>
<Avatar alt="一只可爱的猫咪" :src="src" />
<Avatar alt="姜鹏志" :src="src" />
</template>
Describe the avatar content with alternative text. Avoid empty text and redundant words such as "picture". Declare an action with @click; the component supplies a Tab stop and activates the click on Enter and Space.
Design Tokens
| Sass variable | Value | Usage |
|---|---|---|
| $animation_duration-additionalBorder | 800ms | 边框动画持续时间 |
| $animation_duration-content | 1000ms | 内容动画持续时间 |
| $animation_opacity-additionalBorder-start | 1 | 边框动画起始透明度 |
| $animation_opacity-additionalBorder-end | 0 | 边框动画结束透明度 |
| $animation_scale-additionalBorder-start | 1 | 边框动画起始缩放比例 |
| $animation_scale-additionalBorder-end | 1.15 | 边框动画结束缩放比例 |
| $animation_scale-content-start | 1 | 边框动画起始缩放比例 |
| $animation_scale-content-middle | 0.9 | 边框动画中间态缩放比例 |
| $z-avatar-default | 100 | 头像 z-index |
| $color-avatar_default-border-default | var(--semi-color-bg-1) | 头像描边颜色 |
| $color-avatar_more_default-bg-default | var(--semi-grey-5) | 「更多」描边颜色 |
| $color-avatar-outline-focus | $color-focus-ring | 头像聚焦轮廓颜色 |
| $width-avatar_extra_extra_small | 20px | 头像尺寸 - 极小 |
| $font-avatar_extra_extra_small-size | 10px | 文本字号 - 极小 |
| $font-avatar_extra_extra_small-lineHeight | 15px | 文本行高 - 极小 |
| $width-avatar_extra_small | 24px | 头像尺寸 - 超小 |
| $font-avatar_extra_small-size | 10px | 文本字号 - 超小 |
| $font-avatar_extra_small-lineHeight | 15px | 文本行高 - 超小 |
| $width-avatar_small | 32px | 头像尺寸 - 小 |
| $width-avatar_default | 40px | 头像尺寸 - 默认 |
| $width-avatar_medium | 48px | 头像尺寸 - 中 |
| $width-avatar_large | 72px | 头像尺寸 - 大 |
| $width-avatar_extra_large | 128px | 头像尺寸 - 超大 |
| $font-avatar_extra_large-size | 64px | 文本字号 - 超大 |
| $font-avatar_extra_large-lineHeight | 77px | 文本行高 - 超大 |
| $radius-avatar | var(--semi-border-radius-circle) | 头像圆角 |
| $width-avatar_extra_large-border | 3px | 头像组头像描边尺寸 - 超大 |
| $spacing-avatar_extra_large-marginLeft | -32px | 头像组头像左侧外边距 - 超大 |
| $width-avatar_large-border | 3px | 头像组头像描边尺寸 - 大 |
| $spacing-avatar_large-marginLeft | -18px | 头像左侧外边距 - 大 |
| $width-avatar_medium-border | 2px | 头像组头像描边尺寸 - 中 |
| $spacing-avatar_medium-marginLeft | -12px | 头像左侧外边距 - 中 |
| $width-avatar_default-border | 2px | 头像组头像描边尺寸 - 默认 |
| $spacing-avatar_default-marginLeft | -12px | 头像左侧外边距 - 默认 |
| $width-avatar_small-border | 2px | 头像组头像描边尺寸 - 小 |
| $spacing-avatar_small-marginLeft | -12px | 头像左侧外边距 - 小 |
| $width-avatar_extra_small-border | 1px | 头像组头像描边尺寸 - 超小 |
| $spacing-avatar_extra_small-marginLeft | -10px | 头像左侧外边距 - 超小 |
| $width-avatar_extra_extra_small-border | 1px | 头像组头像描边尺寸 - 极小 |
| $spacing-avatar_extra_extra_small-marginLeft | -4px | 头像左侧外边距 - 极小 |
| $width-avatar-outline | $width-focus-ring | 头像聚焦轮廓宽度 |
| $width-avatar_additional-border | 1.5px | 额外描边尺寸 |
| $color-avatar_additional-border | var(--semi-color-primary) | 额外描边颜色 |
| $spacing-avatar_additional-borderGap | 2px | 额外描边与内侧间距 |
| $width-avatar-bottom_slot_circle_extra_small | 12px | extra small 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_small | 12px | small 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_default | 16px | default 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_medium | 18px | medium 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_large | 28px | large 头像底部 slot 圆形半径 |
| $width-avatar-bottom_slot_circle_extra_large | 28px | extra large 头像底部 slot 圆形半径 |
| $color-avatar-bottom_slot_bg | var(--semi-color-primary) | 头像底部 slot 背景色 |
| $radius-avatar-bottom_slot_square | 4px | 底部 slot square 圆角 |
| $font-avatar_bottom_slot-extra_small-fontSize | 5px | extra small 底部 slot 文字大小 |
| $font-avatar_bottom_slot-small-fontSize | 5px | small 底部 slot 文字大小 |
| $font-avatar_bottom_slot-default-fontSize | 12px | default 底部 slot 文字大小 |
| $font-avatar_bottom_slot-medium-fontSize | 12px | medium 底部 slot 文字大小 |
| $font-avatar_bottom_slot-large-fontSize | 12px | large 底部 slot 文字大小 |
| $font-avatar_bottom_slot-extra_large-fontSize | 14px | extra large 底部 slot 文字大小 |
| $spacing-avatar-bottom_slot_square-paddingX | 4px | 底部 slot square 形状左边距 |
| $spacing-avatar-bottom_slot_square-paddingY | 1px | 底部 slot square 形状右边距 |
| $font-avatar_top_slot-small-fontSize | 5px | small 顶部 slot 文字大小 |
| $font-avatar_top_slot-default-fontSize | 6px | default 顶部 slot 文字大小 |
| $font-avatar_top_slot-medium-fontSize | 8px | medium 顶部 slot 文字大小 |
| $font-avatar_top_slot-large-fontSize | 14px | large 顶部 slot 文字大小 |
| $font-avatar_top_slot-extra_large-fontSize | 16px | extra large 顶部 slot 文字大小 |
| $spacing-avatar-top_slot_small-content-marginTop | 0px | small 顶部文字 marginTop |
| $spacing-avatar-top_slot_default-content-marginTop | -2px | default 顶部文字 marginTop |
| $spacing-avatar-top_slot_medium-content-marginTop | 0px | medium 顶部文字 marginTop |
| $spacing-avatar-top_slot_large-content-marginTop | 0px | large 顶部文字 marginTop |
| $spacing-avatar-top_slot_extra_large-content-marginTop | 0px | extra large 顶部文字 marginTop |
| $color-avatar-bottom_slot_square-border | var(--semi-color-bg-0) | 底部 square 边框颜色 |
| $width-avatar-bottom_slot_square_extra_small-border | 2px | small 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_small-border | 2px | small 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_default-border | 2px | default 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_medium-border | 2px | medium 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_large-border | 2px | large 头像底部 square 边框宽度 |
| $width-avatar-bottom_slot_square_extra_large-border | 2px | extra large 头像底部 square 边框宽度 |
| $color-avatar-top_slot_text | var(--semi-color-bg-0) | 顶部 Slot 文字颜色 |
| $spacing-avatar-top_slot_small-shift | -28px | small 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_default-shift | -32px | default 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_medium-shift | -30px | medium 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_large-shift | -30px | large 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_extra_large-shift | -32px | extra large 顶部 slot 偏移量, 和 scale 一起控制 slot 的位置 |
| $spacing-avatar-top_slot_small-scale | 0.4 | small 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_default-scale | 0.7 | default 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_medium-scale | 0.8 | medium 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_large-scale | 1.1 | large 顶部 slot 缩放比例 |
| $spacing-avatar-top_slot_extra_large-scale | 1.4 | large 顶部 slot 缩放比例 |
| $radius-avatar_extra_extra_small | 3px | 极小尺寸头像的圆角 |
| $radius-avatar_extra_small | 3px | 超小尺寸头像的圆角 |
| $radius-avatar_small | 3px | 小尺寸头像的圆角 |
| $radius-avatar_default | 3px | 默认尺寸头像的圆角 |
| $radius-avatar_medium | 3px | 中尺寸头像的圆角 |
| $radius-avatar_large | 6px | 大尺寸头像的圆角 |
| $radius-avatar_extra_large | 12px | 超大尺寸头像的圆角 |