Progress
Progress is a simple progress bar that can be used to show the progress of a task such as downloading a file, uploading an image, etc.
Features
- Support for linear and circular progress bars.
- Support for minimum and maximum values.
- Support for indeterminate progress bars.
Installation
To use the progress machine in your project, run the following command in your command line:
npm install @zag-js/progress @zag-js/react # or yarn add @zag-js/progress @zag-js/react
npm install @zag-js/progress @zag-js/solid # or yarn add @zag-js/progress @zag-js/solid
npm install @zag-js/progress @zag-js/vue # or yarn add @zag-js/progress @zag-js/vue
npm install @zag-js/progress @zag-js/svelte # or yarn add @zag-js/progress @zag-js/svelte
This command will install the framework agnostic progress logic and the reactive utilities for your framework of choice.
Anatomy
To set up the progress 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 progress package into your project
import * as progress from "@zag-js/progress"
The progress package exports two key functions:
machine
— The state machine logic for the progress 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 progress machine in your project 🔥
import * as progress from "@zag-js/progress" import { normalizeProps, useMachine } from "@zag-js/react" import { useId } from "react" function Progress() { const [state, send] = useMachine(progress.machine({ id: useId() })) const api = progress.connect(state, send, normalizeProps) return ( <div {...api.getRootProps()}> <div {...api.getLabelProps()}>Upload progress</div> <svg {...api.getCircleProps()}> <circle {...api.getCircleTrackProps()} /> <circle {...api.getCircleRangeProps()} /> </svg> </div> ) }
import * as progress from "@zag-js/progress" import { normalizeProps, useMachine } from "@zag-js/solid" import { createMemo, createUniqueId } from "solid-js" function Progress() { const [state, send] = useMachine(progress.machine({ id: useId() })) const api = createMemo(() => progress.connect(state, send, normalizeProps)) return ( <div {...api().getRootProps()}> <div {...api().getLabelProps()}>Upload progress</div> <svg {...api().getCircleProps()}> <circle {...api().getCircleTrackProps()} /> <circle {...api().getCircleRangeProps()} /> </svg> </div> ) }
<script setup> import * as progress from "@zag-js/progress" import { normalizeProps, useMachine } from "@zag-js/vue" import { computed } from "vue" const [state, send] = useMachine(progress.machine({ id: "1" })) const api = computed(() => progress.connect(state.value, send, normalizeProps), ) </script> <template> <div v-bind="api.getRootProps()"> <div v-bind="api.getLabelProps()">Upload progress</div> <svg v-bind="api.getCircleProps()"> <circle v-bind="api.getCircleTrackProps()" /> <circle v-bind="api.getCircleRangeProps()" /> </svg> </div> </template>
<script lang="ts"> import * as progress from "@zag-js/progress" import { normalizeProps, useMachine } from "@zag-js/svelte" const [snapshot, send] = useMachine(progress.machine({ id: "1" })) const api = $derived(progress.connect(snapshot, send, normalizeProps)) </script> <div {...api.getRootProps()}> <div {...api.getLabelProps()}>Upload progress</div> <svg {...api.getCircleProps()}> <circle {...api.getCircleTrackProps()} /> <circle {...api.getCircleRangeProps()} /> </svg> </div>
Setting the value
Use the api.setValue
method to set the value of the progress bar.
const [state, send] = useMachine( progress.machine({ value: 50, }), )
Setting the minimum and maximum values
By default, the progress bar has a minimum value of 0
and a maximum value of
100
. You can change these values by passing the min
and max
options to the
machine.
const [state, send] = useMachine( progress.machine({ min: 0, max: 1000, }), )
Using the indeterminate state
The progress component is determinate by default, with the value and max set to
50
and 100
respectively.
Set value
to null
to indicate an indeterminate value for operations whose
progress can't be determined (e.g., attempting to reconnect to a server).
const [state, send] = useMachine( progress.machine({ value: null, }), )
Showing a value text
Progress bars can only be interpreted by sighted users. To include a text
description to support assistive technologies like screen readers, use the
valueText
part.
const [state, send] = useMachine( progress.machine({ translations: { valueText: ({ value, max }) => value == null ? "Loading..." : `${value} of ${max} items loaded`, }, }), )
Setting the size of the progress bar
Use the --size
CSS variable to set the size of the progress bar.
[data-scope="progress"][data-part="circle"] { --size: 400px; }
Setting the thickness of the progress bar
Use the --thickness
CSS variable to set the size of the progress bar.
[data-scope="progress"][data-part="circle"] { --thickness: 4px; }
Then you need to render the valueText
part in your component.
<div {...api.getValueTextProps()}>{api.valueAsString}</div>
Styling guide
Earlier, we mentioned that each menu part has a data-part
attribute added to
them to select and style them in the DOM.
[data-scope="progress"][data-part="root"] { /* Styles for the root part */ } [data-scope="progress"][data-part="circle-track"] { /* Styles for the track part */ } [data-scope="progress"][data-part="circle-range"] { /* Styles for the range part */ }
Indeterminate state
To style the indeterminate state, you can use the [data-state=indeterminate]
selector.
[data-scope="progress"][data-part="root"][data-state="indeterminate"] { /* Styles for the root indeterminate state */ } [data-scope="progress"][data-part="circle-track"][data-state="indeterminate"] { /* Styles for the root indeterminate state */ } [data-scope="progress"][data-part="circle-range"][data-state="indeterminate"] { /* Styles for the root indeterminate state */ }
Methods and Properties
Machine Context
The progress machine exposes the following context properties:
ids
Partial<{ root: string; track: string; label: string; circle: string; }>
The ids of the elements in the progress bar. Useful for composition.value
number
The current value of the progress bar.min
number
The minimum allowed value of the progress bar.max
number
The maximum allowed value of the progress bar.translations
IntlTranslations
The localized messages to use.dir
"ltr" | "rtl"
The document's text/writing direction.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.orientation
Orientation
The orientation of the element.
Machine API
The progress api
exposes the following methods:
value
number
The current value of the progress bar.valueAsString
string
The current value of the progress bar as a string.setValue
(value: number) => void
Sets the current value of the progress bar.setToMax
() => void
Sets the current value of the progress bar to the max value.setToMin
() => void
Sets the current value of the progress bar to the min value.percent
number
The percentage of the progress bar's value.percentAsString
string
The percentage of the progress bar's value as a string.min
number
The minimum allowed value of the progress bar.max
number
The maximum allowed value of the progress bar.indeterminate
boolean
Whether the progress bar is indeterminate.
Data Attributes
Edit this page on GitHub