Components
Progress
See also: Spinner.
Indeterminate
<script setup lang="ts">import { Progress } from "opui-css/vue"</script>
<template> <Progress aria-busy="true" /></template><div class="ui-progress"> <progress aria-busy="true"><!--[--><!--]--></progress></div>Determinate
<script setup lang="ts">import { onMounted } from "vue"import { Progress } from "opui-css/vue"
onMounted(() => { const progress = document.querySelector<HTMLProgressElement>( "#determinate-progress", ) if (progress) { setInterval(() => { if (progress.value >= 100) { progress.value = 10 } else { progress.value += 10 } }, 3000) }})</script>
<template> <Progress id="determinate-progress" max="100" value="10" /></template><div class="ui-progress"> <progress id="determinate-progress" max="100" value="10"> <!--[--><!--]--> </progress></div>Variants
Use the variant prop to swap the progress bar track surface for better contrast on different backgrounds.
<script setup lang="ts">import { Progress } from "opui-css/vue"</script>
<template> <Progress value="25" max="100" variant="default" /> <Progress value="50" max="100" variant="filled" /> <Progress value="75" max="100" variant="tonal" /></template><!--[--><div class="ui-progress ui-default"> <progress max="100" value="25"><!--[--><!--]--></progress></div><div class="ui-progress ui-filled"> <progress max="100" value="50"><!--[--><!--]--></progress></div><div class="ui-progress ui-tonal"> <progress max="100" value="75"><!--[--><!--]--></progress></div><!--]-->Accessibility
If the <progress> element is describing the loading progress of a section of a page:
- use
aria-describedbyto point to the status - set
aria-busy="true"on the section that is being updated, removing it when loading is finished.
Source: MDN
Content here is loading.
API
Progress API
| Prop | Type | Default | Description |
|---|---|---|---|
aria-busy | boolean, "true", "false" | - | Whether the progress is busy. Passed to the <progress>. |
aria-describedby | string | - | The id of an element that describes the progress. Passed to the <progress>. |
aria-label | string | - | The accessible label. Passed to the <progress>. |
id | string | - | The id of the <progress>. |
max | string, number | - | The maximum value. |
value | string, number | - | The current value. Omit it for an indeterminate state. |
variant | "default", "tonal", "filled" | - | The variant to use. |
Slots
| Slot | Description |
|---|---|
default | Fallback content inside the <progress>. |
Attributes that aren't props also go to the <progress>.
Installation
@layer components.root { :where(.ui-progress) { --_motion: var(--motion, 1); --_accent-color: var(--primary); --_bg-color: var(--surface-tonal);
background-color: var(--_bg-color); block-size: var(--size-1); border-radius: var(--border-radius, 0.25rem); display: inline-block; inline-size: 100%; overflow: hidden; position: relative; vertical-align: baseline;
/* Color */ &.ui-filled { --_bg-color: var(--surface-filled); }
&.ui-default { --_bg-color: var(--surface-default); }
&.ui-tonal { --_bg-color: var(--surface-tonal); }
& > progress { appearance: none; background: none; block-size: 100%; border: 0; display: block; inline-size: 100%;
&::-webkit-progress-bar { background: none; border-radius: var(--border-radius, 0.25rem); }
&[value]::-webkit-progress-value { background-color: var(--_accent-color); transition: inline-size calc(0.2s * var(--_motion)) var(--ease-out-4, cubic-bezier(0, 0, 0.1, 1)); }
&::-moz-progress-bar { background-color: var(--_accent-color); } } }
:where(.ui-progress):has(> progress:indeterminate) { &::after { animation: indeterminate calc(2s * var(--motion, 1)) linear infinite; background-color: var(--_accent-color); content: ""; inset: 0 auto 0 0; position: absolute; will-change: inset-inline-start, inset-inline-end; }
& > progress { &::-webkit-progress-value { background-color: transparent; }
&::-moz-progress-bar { background-color: transparent; } } }
[dir="rtl"] { :where(.ui-progress):has(> progress:indeterminate) { &::after { animation-direction: reverse; } } }
@keyframes indeterminate { 0% { inset-inline-end: 100%; inset-inline-start: -200%; }
60% { inset-inline-end: -8%; inset-inline-start: 107%; }
100% { inset-inline-end: -8%; inset-inline-start: 107%; } }}