Unstyled accessible progress bar root (role="progressbar"); compose with ProgressIndicatorPrimitive and style it yourself.
import ProgressRootPrimitive from "@wikicasa-dev/components/UIKit/ProgressBar/ProgressRootPrimitive";
The library has no ready-made progress bar: build one from ProgressRootPrimitive (the track) and ProgressIndicatorPrimitive (the fill). Both are unstyled <div>s (reka-ui Progress), so all visuals are yours. The root handles accessibility: role="progressbar", aria-valuemin="0", aria-valuemax, aria-valuenow, and an aria-label from get-value-label (default: the rounded percentage, e.g. "40%").
Value rules: model-value between 0 and max (default 100). null/undefined means indeterminate. Out-of-range values are logged as errors and reset to null.
Usage
A listing-completion bar (5 of 8 steps):
<script setup lang="ts">
import { ref } from "vue";
import ProgressRootPrimitive from "@wikicasa-dev/components/UIKit/ProgressBar/ProgressRootPrimitive";
import ProgressIndicatorPrimitive from "@wikicasa-dev/components/UIKit/ProgressBar/ProgressIndicatorPrimitive";
const stepsDone = ref(5);
const totalSteps = 8;
</script>
<template>
<ProgressRootPrimitive
v-model="stepsDone"
:max="totalSteps"
:get-value-label="(value, max) => `Annuncio completato: ${value ?? 0} di ${max} passaggi`"
class="progress"
>
<ProgressIndicatorPrimitive
class="progress__fill"
:style="{ transform: `translateX(-${100 - (stepsDone / totalSteps) * 100}%)` }"
/>
</ProgressRootPrimitive>
</template>
<style scoped>
.progress { position: relative; overflow: hidden; height: 8px; border-radius: 8px; background: rgb(var(--uikit-color-w-lavender)); }
.progress__fill { width: 100%; height: 100%; background: rgb(var(--uikit-color-w-primary)); transition: transform 0.3s ease; }
.progress[data-state="complete"] .progress__fill { background: #358500; }
</style>
Do / Don't
- Do position the fill yourself (the
transformabove, or awidthin %); the indicator never moves on its own. - Do give the root
overflow: hidden, a height and a background: it is the track. - Do pass a descriptive
get-value-label: its result is the bar'saria-label. Useget-value-textforaria-valuetext. - Don't pass values above
maxor below 0. - The default slot receives
{ modelValue }, handy for a "62%" label inside the track.
Styling hooks
Both root and indicator carry data-state (indeterminate, loading, complete), data-value and data-max. Use [data-state="indeterminate"] for an animated "unknown duration" look and [data-state="complete"] for a finished color.
API
Generated from the component's types. Do not edit by hand.
Props
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
modelValue |
number | null |
The progress value. Can be bind as v-model. |
||
max |
number |
The maximum progress value. | ||
getValueLabel |
((value: number | null | undefined, max: number) => string | undefined) |
A function to get the accessible label text in a human-readable format. If not provided, the value label will be read as the numeric value as a percentage of the max value. | ||
getValueText |
((value: number | null | undefined, max: number) => string | undefined) |
A function to get the accessible value text representing the current value in a human-readable format. | ||
asChild |
boolean |
Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | ||
as |
AsTag | Component |
The element or component this component should render as. Can be overwritten by asChild. |
Events
| Name | Payload |
|---|---|
update:modelValue |
[value: string[] | undefined] |
update:max |
[value: number] |
v-model
v-modelbindsmodelValue(number \| null)v-model:max(number)
Slots
| Name | Slot props |
|---|---|
default |
{ modelValue: number | null | undefined; } |
Exposed (template ref)
None.