Progress
A headless progress bar component for building determinate, indeterminate, and buffered loading indicators. Uses createProgress internally, which delegates segment tracking to createModel.
Usage
The Progress supports single-value and multi-segment modes. Bind a number for a single bar, or an array for multiple segments.
<script setup lang="ts">
import { Progress, Slider } from '@vuetify/v0'
import { shallowRef } from 'vue'
const value = shallowRef(65)
</script>
<template>
<div class="flex flex-col gap-4 w-full">
<Progress.Root v-model="value">
<Progress.Label class="text-sm font-medium">Loading...</Progress.Label>
<Progress.Track class="relative h-2 w-full overflow-hidden rounded-full bg-surface-variant">
<Progress.Fill class="h-full rounded-full bg-primary" />
</Progress.Track>
<Progress.Value class="text-sm text-neutral-500" />
</Progress.Root>
<Slider.Root v-model="value" class="relative flex items-center w-full h-5">
<Slider.Track class="relative h-1 w-full rounded-full bg-surface-variant">
<Slider.Range class="absolute h-full rounded-full bg-primary" />
</Slider.Track>
<Slider.Thumb class="absolute size-5 rounded-full bg-primary -translate-x-1/2 focus:outline-2 focus:outline-primary" />
</Slider.Root>
</div>
</template>
Anatomy
<script setup lang="ts">
import { Progress } from '@vuetify/v0'
</script>
<template>
<Progress.Root>
<Progress.Label />
<Progress.Track>
<Progress.Fill />
<Progress.Buffer />
</Progress.Track>
<Progress.Value />
<Progress.HiddenInput />
</Progress.Root>
</template>Examples
Storage Usage
Multi-segment progress bar showing disk usage by category. Each Progress.Fill registers as a segment with its own value, and Root aggregates them into a total.
File breakdown:
| File | Role |
|---|---|
StorageBar.vue | Reusable component — renders a multi-segment bar with category colors and a total label |
storage.vue | Demo — wires category data with interactive sliders to adjust values |
Key patterns:
Multiple
Progress.Fillcomponents register segments via the internal model registry — their values sum to the totalProgress.Value v-slot="{ total }"provides the aggregate for custom formatting:max="128"on Root sets the upper bound so percentages compute against 128 GB instead of the default 100
Media Player
A media player progress bar with buffer indicator. The buffer shows pre-loaded content while the fill tracks playback position.
File breakdown:
| File | Role |
|---|---|
MediaProgress.vue | Reusable component — thin bar with buffer and fill layers |
media.vue | Demo — simulates playback with play/pause/reset controls |
Key patterns:
Progress.Bufferis independent of the segment registry — it readsvaluedirectly and computes its own percentage against Root’s min/maxBuffer and Fill are both
absolute inset-y-0 left-0so they layer correctly, with Fill rendering on top via DOM orderThe timer increments both values at different rates to simulate realistic buffering ahead of playback
Recipes
Indeterminate State
When no value is provided (or all segment values are 0), the progress is indeterminate. Use data-state to apply CSS animations:
<template>
<Progress.Root>
<Progress.Track class="relative h-2 w-full overflow-hidden rounded-full bg-neutral-200">
<Progress.Fill class="h-full rounded-full bg-blue-500 data-[state=indeterminate]:animate-pulse data-[state=indeterminate]:w-full" />
</Progress.Track>
</Progress.Root>
</template>Custom Value Format
Override the default ${percent}% display via the scoped slot:
<template>
<Progress.Value v-slot="{ total, percent }">
{{ total }} of 100 ({{ Math.round(percent) }}%)
</Progress.Value>
</template>Form Integration
Set name on Root to auto-render a hidden input for form submission:
<template>
<Progress.Root v-model="value" name="upload-progress">
<Progress.Track>
<Progress.Fill />
</Progress.Track>
</Progress.Root>
</template>Data Attributes
Style states without slot props:
<template>
<Progress.Fill class="data-[state=indeterminate]:animate-pulse transition-all" />
</template>| Attribute | Values | Components |
|---|---|---|
data-state | determinate, indeterminate | Root, Track, Fill, Buffer |
data-complete | true | Root |
data-buffer | true | Buffer |
data-index | number | Fill |
Accessibility
The Root component manages ARIA attributes automatically.
ARIA Attributes
| Attribute | Value | Notes |
|---|---|---|
role | progressbar | Applied to Root |
aria-valuenow | Current total | Omitted when indeterminate |
aria-valuemin | Min value | From Root’s min prop (default 0) |
aria-valuemax | Max value | From Root’s max prop (default 100) |
aria-valuetext | ${percent}% | Omitted when indeterminate |
aria-labelledby | Label ID | Links to Progress.Label |
aria-busy | true | Set when indeterminate |
data-state | determinate / indeterminate | Reflects current mode |
data-complete | true | When total >= max |
Progress.Root
Props
Slots
default
ProgressRootSlotPropsProgress.Buffer
Props
namespace
string | undefinedNamespace for context injection from parent Progress.Root
Default: "v0:progress:root"
Slots
default
ProgressBufferSlotPropsProgress.Fill
Props
Slots
default
ProgressFillSlotPropsProgress.HiddenInput
Props
namespace
string | undefinedNamespace for context injection from parent Progress.Root
Default: "v0:progress:root"
Progress.Label
Props
Slots
default
ProgressLabelSlotPropsProgress.Track
Props
namespace
string | undefinedNamespace for context injection from parent Progress.Root
Default: "v0:progress:root"
Slots
default
ProgressTrackSlotPropsProgress.Value
Props
namespace
string | undefinedNamespace for context injection from parent Progress.Root
Default: "v0:progress:root"
Slots
default
ProgressValueSlotProps