Avatar
An avatar represents a user profile picture. It displays an image or fallback content in a container.
Avatar supports fallback text or elements when the image fails to load or when no image is provided.
Installation
Install the avatar package:
npm install @zag-js/avatar @zag-js/react # or yarn add @zag-js/avatar @zag-js/react
npm install @zag-js/avatar @zag-js/solid # or yarn add @zag-js/avatar @zag-js/solid
npm install @zag-js/avatar @zag-js/vue # or yarn add @zag-js/avatar @zag-js/vue
npm install @zag-js/avatar @zag-js/svelte # or yarn add @zag-js/avatar @zag-js/svelte
Anatomy
Check the avatar anatomy and part names.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
Import the avatar package:
import * as avatar from "@zag-js/avatar"
The avatar package exports two key functions:
machine- State machine logic.connect- Maps machine state to JSX props and event handlers.
Pass a unique
idtouseMachineso generated element ids stay predictable.
Then use the framework integration helpers:
import * as avatar from "@zag-js/avatar" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" function Avatar() { const service = useMachine(avatar.machine, { id: useId() }) const api = avatar.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <span {...api.getFallbackProps()}>PA</span> <img alt="PA" src={src} {...api.getImageProps()} /> </div> ) }
import * as avatar from "@zag-js/avatar" import { useMachine, normalizeProps } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" function Avatar() { const service = useMachine(avatar.machine, { id: createUniqueId() }) const api = createMemo(() => avatar.connect(service, normalizeProps)) return ( <div {...api().getRootProps()}> <span {...api().getFallbackProps()}>PA</span> <img alt="PA" src={src} {...api().getImageProps()} /> </div> ) }
<script setup> import * as avatar from "@zag-js/avatar" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const service = useMachine(avatar.machine, { id: "1" }) const api = computed(() => avatar.connect(service, normalizeProps)) </script> <template> <div v-bind="api.getRootProps()"> <span v-bind="api.getFallbackProps()">PA</span> <img alt="PA" :src="src" v-bind="api.getImageProps()" /> </div> </template>
<script lang="ts"> import * as avatar from "@zag-js/avatar" import { useMachine, normalizeProps } from "@zag-js/svelte" const id = $props.id() const service = useMachine(avatar.machine, ({ id })) const api = $derived(avatar.connect(service, normalizeProps)) </script> <div {...api.getRootProps()}> <span {...api.getFallbackProps()}>PA</span> <img alt="PA" src={src} {...api.getImageProps()} /> </div>
Loading status
The image loading status is loading, loaded, or error. Read the current
value from api.status, or react to changes with onStatusChange.
const service = useMachine(avatar.machine, { onStatusChange(details) { // details => { status: "loading" | "error" | "loaded" } }, })
Updating the image source
In framework adapters, update the image src through your own state. The
machine watches the rendered image and reacts automatically, resetting to
loading and then to loaded or error.
For imperative usage like vanilla JS, api.setSrc sets the source on the
machine's image element directly.
api.setSrc(nextSrc)
Styling guide
Each avatar part includes a data-part attribute you can target in CSS.
[data-scope="avatar"][data-part="root"] { /* Styles for the root part */ } [data-scope="avatar"][data-part="image"] { /* Styles for the image part */ } [data-scope="avatar"][data-part="fallback"] { /* Styles for the fallback part */ }
Creating a component
Create your avatar component by abstracting the machine into your own component.
Usage
import { Avatar } from "./your-avatar" function Demo() { return ( <Avatar src="https://avatars.githubusercontent.com/u/139426" name="John Doe" /> ) }
Implementation
Use the splitProps utility to separate the machine's props from the
component's props.
import * as avatar from "@zag-js/avatar" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" export interface AvatarProps extends Omit<avatar.Context, "id"> { /** * The src of the avatar image */ src?: string /** * The srcSet of the avatar image */ srcSet?: string /** * The name of the avatar */ name: string } function Avatar(props: AvatarProps) { const [machineProps, localProps] = avatar.splitProps(props) const service = useMachine(avatar.machine, { id: useId(), ...machineProps, }) const api = avatar.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <span {...api.getFallbackProps()}>{getInitials(localProps.name)}</span> <img alt="PA" src={localProps.src} srcSet={localProps.srcSet} {...api.getImageProps()} /> </div> ) } function getInitials(name: string) { return name .split(" ") .map((word) => word[0]) .join("") }
Methods and Properties
Machine Context
The avatar machine exposes the following context properties:
onStatusChange((details: StatusChangeDetails) => void) | undefinedFunctional called when the image loading status changes.idsElementIds | undefinedThe ids of the elements in the avatar. Useful for composition.idstringThe unique identifier of the machine.getRootNode(() => ShadowRoot | Document | Node) | undefinedA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.dir"ltr" | "rtl" | undefinedThe document's text/writing direction.
Machine API
The avatar api exposes the following methods:
statusLoadStatusThe current image loading status.loadedbooleanWhether the image is loaded.setSrc(src: string) => voidFunction to set new src.setLoadedVoidFunctionFunction to set loaded state.setErrorVoidFunctionFunction to set error state.