Progress

Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.

Examples

Basic

PropDefaultTypeDescription
modelValue-numberThe progress value. Can be bind as v-model.
max100numberThe maximum progress value.
indeterminatefalsebooleanMakes the progress bar indeterminate. When true, the progress bar will animate without a specific value.
getValueLabel${Math.round((value / max) * DEFAULT_MAX)}%((value: number, max: number) => string)A function to get the accessible label text representing the current value 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.
Preview
Code

Color

PropDefaultTypeDescription
progressprimarystringSets the color of the progress bar.
Preview
Code

Size

PropDefaultTypeDescription
sizemdstringSets the size of the progress bar.
Preview
Code

Customization

Configure the progress using the una prop and utility classes.

Preview
Code

Slots

NamePropsDescription
default-The progress indicator.

Presets

shortcuts/progress.ts
import type { RuleContext } from '@unocss/core'
import type { Theme } from '@unocss/preset-uno'
import { parseColor } from '@unocss/preset-mini/utils'

type ProgressPrefix = 'progress'

export const staticProgress: Record<`${ProgressPrefix}-${string}`, string> = {
  // base
  'progress-indeterminate': 'absolute bg-brand h-full',

  // components
  'progress-root': 'relative h-0.5em w-full overflow-hidden rounded-full bg-brand/20',
  'progress-indicator': 'h-full w-full flex-1 bg-brand transition-all',
}

export const dynamicProgress = [
  [/^progress-(.*)$/, ([, body]: string[], { theme }: RuleContext<Theme>) => {
    const color = parseColor(body, theme)
    if ((color?.cssColor?.type === 'rgb' || color?.cssColor?.type === 'rgba') && color.cssColor.components)
      return `n-${body}-600 dark:n-${body}-500`
  }],
]
export const progress = [
  ...dynamicProgress,
  staticProgress,
]

Props

types/progress.ts
import type { ProgressRootProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'

type Extensions = ProgressRootProps & { class?: HTMLAttributes['class'] }

export interface NProgressProps extends Extensions {
  /**
   * Allows you to add `UnaUI` progress preset properties,
   * Think of it as a shortcut for adding options or variants to the preset if available.
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/progress.ts
   * @example
   * progress="red""
   */
  progress?: string
  /**
   * Allows you to change the size of the progress.
   *
   * @default base|md
   *
   * @example
   * size="sm" | size="2cm" | size="2rem" | size="2px"
   */
  size?: string
  /**
   * `UnaUI` preset configuration
   *
   * @see https://github.com/una-ui/una-ui/blob/main/packages/preset/src/_shortcuts/progress.ts
   */
  una?: {
    // components
    progressRoot?: HTMLAttributes['class']
    progressIndicator?: HTMLAttributes['class']
  }
}

Components

Progress.vue
<script setup lang="ts">
import type { NProgressProps } from '../../types'
import {
  ProgressIndicator,
  ProgressRoot,
} from 'radix-vue'
import { computed } from 'vue'
import { cn } from '../../utils'

const props = withDefaults(
  defineProps<NProgressProps>(),
  {
    progress: 'primary',
  },
)

const delegatedProps = computed(() => {
  const { class: _, ...delegated } = props

  return delegated
})
</script>

<template>
  <ProgressRoot
    v-bind="delegatedProps"
    :class="
      cn(
        'progress-root',
        props.una?.progressRoot,
        props.class,
      )
    "
    :progress
  >
    <slot>
      <ProgressIndicator
        v-if="props.modelValue !== undefined || props.modelValue === null"
        :class="cn(
          'progress-indicator',
          props.una?.progressIndicator,
        )"
        :style="`transform: translateX(-${100 - (props.modelValue ?? 0)}%);`"
      />
      <template
        v-else
      >
        <ProgressIndicator
          :class="cn(
            'increase progress-indeterminate',
            props.una?.progressIndicator,
          )"
        />
        <ProgressIndicator
          :class="cn(
            'decrease progress-indeterminate',
            props.una?.progressIndicator,
          )"
        />
      </template>
    </slot>
  </ProgressRoot>
</template>

<style scoped>
.increase.progress-indeterminate {
  animation: progress-indeterminate-increase 2s ease-in-out infinite;
}

.decrease.progress-indeterminate {
  animation: progress-indeterminate-decrease 2s 0.5s ease-in-out infinite;
}

@keyframes progress-indeterminate-decrease {
  0% {
    left: -90%;
    width: 90%;
  }

  100% {
    left: 110%;
    width: 10%;
  }
}

@keyframes progress-indeterminate-increase {
  0% {
    left: -5%;
    width: 5%;
  }

  100% {
    left: 130%;
    width: 150%;
  }
}
</style>