ProgressBar

A progress bar shows either determinate or indeterminate progress of an operation over time.

Usage

import { ProgressBar } from '@hareui/vue'
Loading60%
<script setup lang="ts">import { ProgressBar } from '@hareui/vue'</script><template>  <ProgressBar aria-label="Loading" class="w-64" label="Loading" :value="60" /></template>

Anatomy

HeroUI's Label, ProgressBar.Output, ProgressBar.Track and ProgressBar.Fill parts are rendered by the component, built on Reka UI's ProgressRoot / ProgressIndicator.

<ProgressBar :value="60" label="Loading">
  <template #label /> <!-- optional: replaces the label text -->
  <template #output="{ percentage, valueText, indeterminate }" /> <!-- optional: replaces the value text -->
</ProgressBar>
  • The label renders when the label prop or #label slot is provided, and labels the bar via aria-labelledby.
  • The output renders next to a label unless the bar is indeterminate; set show-output to force it on or off.

ui keys: base, label, output, track, fill.

Examples

Sizes

Small40%
Medium60%
Large80%
<script setup lang="ts">import { ProgressBar } from '@hareui/vue'</script><template>  <div class="flex w-64 flex-col gap-6">    <ProgressBar aria-label="Small" label="Small" size="sm" :value="40" />    <ProgressBar aria-label="Medium" label="Medium" size="md" :value="60" />    <ProgressBar aria-label="Large" label="Large" size="lg" :value="80" />  </div></template>

Colors

Default50%
Accent50%
Success50%
Warning50%
Danger50%
<script setup lang="ts">import { ProgressBar } from '@hareui/vue'</script><template>  <div class="flex w-64 flex-col gap-6">    <ProgressBar aria-label="Default" color="default" label="Default" :value="50" />    <ProgressBar aria-label="Accent" color="accent" label="Accent" :value="50" />    <ProgressBar aria-label="Success" color="success" label="Success" :value="50" />    <ProgressBar aria-label="Warning" color="warning" label="Warning" :value="50" />    <ProgressBar aria-label="Danger" color="danger" label="Danger" :value="50" />  </div></template>

Without Label

When no visible label is needed, use aria-label for accessibility.

<script setup lang="ts">import { ProgressBar } from '@hareui/vue'</script><template>  <ProgressBar aria-label="Loading progress" class="w-64" :value="45" /></template>

Indeterminate

Use indeterminate when progress cannot be determined.

Loading...
<script setup lang="ts">import { ProgressBar } from '@hareui/vue'</script><template>  <ProgressBar aria-label="Loading" class="w-64" indeterminate label="Loading..." /></template>

Custom Value Scale

Use min-value, max-value, and format-options to customize the value range and display format.

Progress75%
Format
<script setup lang="ts">import type { ListBoxItem } from '@hareui/vue'import { Label, NumberField, ProgressBar, Select, Separator } from '@hareui/vue'import { ref } from 'vue'const formatStyleOptions: ListBoxItem[] = [  { label: 'Currency', value: 'currency' },  { label: 'Percent', value: 'percent' },  { label: 'Decimal', value: 'decimal' },  { label: 'Unit', value: 'unit' },]const formatOptionsMap: Record<string, Intl.NumberFormatOptions> = {  currency: { currency: 'USD', style: 'currency' },  decimal: { style: 'decimal' },  percent: { style: 'percent' },  unit: { style: 'unit', unit: 'mile' },}const value = ref(750)const minValue = ref(0)const maxValue = ref(1000)const format = ref('percent')function setMinValue(v: number | null | undefined) {  minValue.value = v ?? 0  if (value.value < minValue.value)    value.value = minValue.value}function setMaxValue(v: number | null | undefined) {  maxValue.value = v ?? minValue.value + 1  if (value.value > maxValue.value)    value.value = maxValue.value}</script><template>  <div class="flex w-full flex-col gap-6 md:flex-row md:items-center md:gap-10">    <div class="flex w-full max-w-md flex-1 justify-center">      <ProgressBar        aria-label="Revenue"        class="w-full max-w-52"        :format-options="formatOptionsMap[format]"        label="Progress"        :max-value="maxValue"        :min-value="minValue"        :value="value"      />    </div>    <Separator class="md:hidden" />    <Separator class="hidden md:block" orientation="vertical" />    <div class="flex max-w-52 flex-col gap-3">      <Label class="text-xs font-medium text-muted">Options</Label>      <NumberField v-model="value" label="Value" :max="maxValue" :min="minValue" variant="secondary" />      <NumberField        label="Min Value"        :max="maxValue - 1"        :min="0"        :model-value="minValue"        variant="secondary"        @update:model-value="setMinValue"      />      <NumberField        label="Max Value"        :max="2000"        :min="minValue + 1"        :model-value="maxValue"        variant="secondary"        @update:model-value="setMaxValue"      />      <Select v-model="format" :items="formatStyleOptions" label="Format" variant="secondary" />    </div>  </div></template>

Customization

Tailwind CSS

Use the class prop for the root and the ui prop for the label, output, track and fill:

Uploading resume.pdf45%
<script setup lang="ts">import { ProgressBar } from '@hareui/vue'</script><template>  <ProgressBar    aria-label="Upload progress"    class="w-64"    label="Uploading resume.pdf"    :ui="{      label: 'font-medium text-foreground',      output: 'text-xs text-muted tabular-nums',      track: 'rounded-full bg-default',      fill: 'rounded-full bg-accent',    }"    :value="45"  /></template>

Global theme override

Override the progressBar theme app-wide with createHareUI:

app.use(createHareUI({
  ui: {
    progressBar: {
      slots: {
        base: 'w-full gap-2',
        track: 'h-3 rounded-full',
        fill: 'rounded-full',
      },
    },
  },
}))

Styling Reference

Each rendered element carries the same data-slot string as HeroUI, so selectors translate 1:1.

ui keydata-slotDescription
baseprogress-barBase container (grid layout)
labellabelLabel text (Label theme plus the grid placement)
outputprogress-bar-outputValue text display
trackprogress-bar-trackTrack background
fillprogress-bar-fillFilled portion of the track

HeroUI's modifier classes correspond to props (HareUI renders utilities, not BEM classes, so style through class, ui or createHareUI):

  • size: sm (thinner track), md (default), lg (thicker track) (.progress-bar--{size})
  • color: default, accent (default), success, warning, danger (.progress-bar--{color})

API Reference

Props

PropTypeDefaultDescription
valuenumber0The current value (clamped to minValue–maxValue).
minValuenumber0The minimum value.
maxValuenumber100The maximum value.
indeterminatebooleanfalseWhether progress is indeterminate (no value; the fill loops).
formatOptionsIntl.NumberFormatOptions{ style: 'percent' }Number format for the value display. Percent formats the fraction of the range.
valueLabelstring-Custom value text (e.g. '3 of 4'), replacing the formatted value in the output and aria-valuetext.
labelstring-Visible label, rendered in the top-left grid area and referenced by aria-labelledby.
showOutputbooleanundefinedWhether to render the value output. Defaults to showing it next to a label, unless indeterminate.
size"md" | "sm" | "lg"'md'Size of the progress track.
color"default" | "accent" | "success" | "warning" | "danger"'accent'Color of the fill bar.
uiComponentSlots<{ slots: { base: string[]; label: string; output: string; track: string; fill: string; }; variants: { color: { default: { base: string; }; accent: { base: string; }; success: { base: string; }; warning: { base: string; }; danger: { base: string; }; }; size: { sm: { track: string; fill: string; }; md: {}; lg: { track: string; fill: string; }; }; indeterminate: { true: { fill: string; }; }; }; defaultVariants: { color: string; size: string; }; }>-Per-slot class overrides.

Slots

SlotPropsDescription
labelProgressBarSlotPropsReplaces the label text.
outputProgressBarSlotPropsReplaces the value output text.

#label and #output receive:

PropTypeDescription
percentagenumber | undefinedThe percentage of the progress (0-100)
valueTextstring | undefinedThe formatted value text
indeterminatebooleanWhether progress is indeterminate

On this page

No Headings