@wikicasa-dev/components · Loading · primitive

ProgressRootPrimitive

Unstyled accessible progress bar root (role="progressbar"); compose with ProgressIndicatorPrimitive and style it yourself.

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 transform above, or a width in %); 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's aria-label. Use get-value-text for aria-valuetext.
  • Don't pass values above max or 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-model binds modelValue (number \| null)
  • v-model:max (number)

Slots

Name Slot props
default { modelValue: number | null | undefined; }

Exposed (template ref)

None.