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 component-scoped data attribute to help identify it 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
You own the image src; the machine observes the rendered image and owns its
loading lifecycle. Update src however you normally would and the machine
reacts, resetting to loading and then to loaded or error.
This holds for srcSet and <picture> too, since the machine watches the
element rather than a value you hand it.
const [src, setSrc] = useState(initialSrc) <img alt="" src={src} {...api.getImageProps()} />
Two cases the machine already covers, so you don't have to:
- An image served from cache can finish loading before the
loadhandler is attached. The machine checks whether the image is already complete. - Setting
srcto a URL that previously failed retries it, rather than staying in the error state.
If the image is loaded by something that doesn't fire load and error on the
element itself, drive the lifecycle with api.setLoaded() and api.setError().
Styling guide
Each part includes a component-scoped data attribute you can target in CSS.
[data-avatar-root] { /* Styles for the root part */ } [data-avatar-image] { /* Styles for the image part */ } [data-avatar-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.setLoadedVoidFunctionFunction to set loaded state.setErrorVoidFunctionFunction to set error state.