Avatar

An image element with a fallback for representing the user.

Sizes
CN CN CN
CNCNCN
Badge
JZ JZ JZ
JZ JZ JZ
Badge with Icon
PP PP PP
PP PP PP
Group
CN LR ER
CN LR ER
CN LR ER
Group with Count
CN LR ER
+3
CN LR ER
+3
CN LR ER
+3
Group with Icon Count
CN LR ER
CN LR ER
CN LR ER
In Empty
CN LR ER
No Team Members
Invite your team to collaborate on this project.

Installation

Install the dependencies

pnpm add cn class-variance-authority github:sveltery/base

Copy the component

Copy the following files into src/lib/components/ui/avatar.

src/lib/components/ui/avatar/Avatar.svelte
<script lang="ts">
  import { Avatar as AvatarPrimitive } from '@sveltery/base/avatar';
  import { cn } from 'cn';
  import type { AvatarProps } from './types.js';
  let { children, class: classProp, size = 'default', ...props }: AvatarProps = $props();
</script>
<AvatarPrimitive.Root
  data-slot="avatar"
  data-size={size}
  class={cn('size-8 rounded-full after:rounded-full data-[size=lg]:size-10 data-[size=sm]:size-6 group/avatar relative flex shrink-0 select-none after:absolute after:inset-0 after:border after:border-border after:mix-blend-darken dark:after:mix-blend-lighten', classProp)}
  {...props}
  {children}
/>
src/lib/components/ui/avatar/AvatarBadge.svelte
<script lang="ts">
  import { cn } from 'cn';
  import type { AvatarBadgeProps } from './types.js';
  let { children, class: classProp, ...props }: AvatarBadgeProps = $props();
</script>
<span
  data-slot="avatar-badge"
  class={cn(
    'bg-primary text-primary-foreground ring-background absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-blend-color ring-2 select-none',
    'group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden',
    'group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2',
    'group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2',
    classProp,
  )}
  {...props}
>
  {@render children?.()}
</span>
src/lib/components/ui/avatar/AvatarFallback.svelte
<script lang="ts">
  import { Avatar as AvatarPrimitive } from '@sveltery/base/avatar';
  import { cn } from 'cn';
  import type { AvatarFallbackProps } from './types.js';
  let { children, class: classProp, ...props }: AvatarFallbackProps = $props();
</script>
<AvatarPrimitive.Fallback
  data-slot="avatar-fallback"
  class={cn('bg-muted text-muted-foreground rounded-full flex size-full items-center justify-center text-sm group-data-[size=sm]/avatar:text-xs', classProp)}
  {...props}
  {children}
/>
src/lib/components/ui/avatar/AvatarGroup.svelte
<script lang="ts">
  import { cn } from 'cn';
  import type { AvatarGroupProps } from './types.js';
  let { children, class: classProp, ...props }: AvatarGroupProps = $props();
</script>
<div
  data-slot="avatar-group"
  class={cn('group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background', classProp)}
  {...props}
>
  {@render children?.()}
</div>
src/lib/components/ui/avatar/AvatarGroupCount.svelte
<script lang="ts">
  import { cn } from 'cn';
  import type { AvatarGroupCountProps } from './types.js';
  let { children, class: classProp, ...props }: AvatarGroupCountProps = $props();
</script>
<div data-slot="avatar-group-count" class={cn('bg-muted text-muted-foreground size-8 rounded-full text-sm group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3 relative flex shrink-0 items-center justify-center ring-2 ring-background', '', classProp)} {...props}>
  {@render children?.()}
</div>
src/lib/components/ui/avatar/AvatarImage.svelte
<script lang="ts">
  import { Avatar as AvatarPrimitive } from '@sveltery/base/avatar';
  import { cn } from 'cn';
  import type { AvatarImageProps } from './types.js';
  let { children, class: classProp, ...props }: AvatarImageProps = $props();
</script>
<AvatarPrimitive.Image data-slot="avatar-image" class={cn('rounded-full aspect-square size-full object-cover', classProp)} {...props} {children} />
src/lib/components/ui/avatar/types.ts
import type { HTMLAttributes } from 'svelte/elements';
import type { AvatarRootProps } from '@sveltery/base/avatar';

export type { AvatarImageProps, AvatarFallbackProps, AvatarRootState, AvatarImageState, AvatarFallbackState, ImageLoadingStatus } from '@sveltery/base/avatar';
export type AvatarProps = AvatarRootProps & { size?: 'default' | 'sm' | 'lg' };
export type AvatarBadgeProps = HTMLAttributes<HTMLSpanElement>;
export type AvatarGroupProps = HTMLAttributes<HTMLDivElement>;
export type AvatarGroupCountProps = HTMLAttributes<HTMLDivElement>;
src/lib/components/ui/avatar/index.ts
export { default as Avatar } from './Avatar.svelte';
export { default as AvatarImage } from './AvatarImage.svelte';
export { default as AvatarFallback } from './AvatarFallback.svelte';
export { default as AvatarBadge } from './AvatarBadge.svelte';
export { default as AvatarGroup } from './AvatarGroup.svelte';
export { default as AvatarGroupCount } from './AvatarGroupCount.svelte';
export type { AvatarProps, AvatarImageProps, AvatarFallbackProps, AvatarBadgeProps, AvatarGroupProps, AvatarGroupCountProps, AvatarRootState, AvatarImageState, AvatarFallbackState, ImageLoadingStatus } from './types.js';

Update the import paths

Change the imports to match your project setup.

Usage

<script lang="ts">
  import { Avatar, AvatarFallback, AvatarImage } from '$lib/components/ui/avatar';
</script>
<Avatar>
  <AvatarImage src="https://github.com/sveltejs.png" alt="@sveltejs" />
  <AvatarFallback>SV</AvatarFallback>
</Avatar>

API reference

Avatar is styled on top of the Sveltery Base Avatar primitive, which owns its behavior, focus handling and accessibility. See the Base UI Avatar documentation for the behavior it ports.