Avatar
The Avatar component is a React component that represents a user avatar or profile picture. It displays an image or initials within container.
Avatar provides support for fallback text or elements when the image fails to load, or when the image is not provided.
Installation
To use the avatar machine in your project, run the following command in your command line:
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/vue # or yarn add @zag-js/avatar @zag-js/vue
This command will install the framework agnostic avatar logic and the reactive utilities for your framework of choice.
Anatomy
To set up the avatar correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-part
attribute to help identify them in the DOM.
Usage
First, import the avatar package into your project
import * as avatar from "@zag-js/avatar"
The avatar package exports two key functions:
machine
— The state machine logic for the avatar widget.connect
— The function that translates the machine's state to JSX attributes and event handlers.
You'll also need to provide a unique
id
to theuseMachine
hook. This is used to ensure that every part has a unique identifier.
Next, import the required hooks and functions for your framework and use the avatar machine in your project 🔥
import * as avatar from "@zag-js/avatar" import { useMachine, normalizeProps } from "@zag-js/react" function Avatar() { const [state, send] = useMachine(avatar.machine({ id: "1" })) const api = avatar.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> <span {...api.fallbackProps}>PA</span> <img alt="PA" src={src} {...api.imageProps} /> </div> ) }
import * as avatar from "@zag-js/avatar" import { useMachine, normalizeProps } from "@zag-js/solid" function Avatar() { const [state, send] = useMachine(avatar.machine({ id: "1" })) const api = createMemo(() => avatar.connect(state, send, normalizeProps)) return ( <div {...api.rootProps}> <span {...api.fallbackProps}>PA</span> <img alt="PA" src={src} {...api.imageProps} /> </div> ) }
import * as avatar from "@zag-js/avatar" import { useMachine, normalizeProps } from "@zag-js/vue" export default defineComponent({ name: "Avatar", setup() { const [state, send] = useMachine(avatar.machine({ id: "1" })) const apiRef = computed(() => avatar.connect(state.value, send, normalizeProps), ) return () => { const api = apiRef.value return ( <div {...api.rootProps}> <span {...api.fallbackProps}>PA</span> <img alt="PA" src={src} {...api.imageProps} /> </div> ) } }, })
<script setup> import * as avatar from "@zag-js/avatar" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const [state, send] = useMachine(avatar.machine({ id: "1" })) const api = computed(() => avatar.connect(state.value, send, normalizeProps)) </script> <template> <div v-bind="api.rootProps"> <span v-bind="api.fallbackProps">PA</span> <img alt="PA" :src="src" v-bind="api.imageProps" /> </div> </template>
Listening for loading status changes
When the image has loaded or failed to load, the onStatusChange
callback is
invoked.
const [state, send] = useMachine( avatar.machine({ onStatusChange(details) { // details => { status: "error" | "loaded" } }, }), )
Styling guide
Earlier, we mentioned that each avatar part has a data-part
attribute added to
them to select and style them in the DOM.
[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 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 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" 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 [state, send] = useMachine(avatar.machine({ id: useId() }), { context: machineProps, }) const api = avatar.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> <span {...api.fallbackProps}>{getInitials(localProps.name)}</span> <img alt="PA" src={localProps.src} srcSet={localProps.srcSet} {...api.imageProps} /> </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
Functional called when the image loading status changes.ids
Partial<{ root: string; image: string; fallback: string; }>
The ids of the elements in the avatar. Useful for composition.id
string
The unique identifier of the machine.getRootNode
() => ShadowRoot | Node | Document
A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.dir
"ltr" | "rtl"
The document's text/writing direction.
Machine API
The avatar api
exposes the following methods:
loaded
boolean
Whether the image is loaded.setSrc
(src: string) => void
Function to set new src.setLoaded
() => void
Function to set loaded state.setError
() => void
Function to set error state.
Edit this page on GitHub