Components
Progress
See also: Spinner.
Indeterminate
---import { Progress } from "@opui/astro"---
<Progress aria-busy="true" /><div class="ui-progress"><progress aria-busy="true"></progress></div>Determinate
---import { Progress } from "@opui/astro"---
<Progress id="determinate-progress" max="100" value="10" />
<script> const progress = document.querySelector( "#determinate-progress", ) as HTMLProgressElement if (progress) { setInterval(() => { if (progress.value >= 100) { progress.value = 10 } else { progress.value += 10 } }, 3000) }</script><div class="ui-progress"> <progress id="determinate-progress" max="100" value="10"></progress></div><script type="module"> var e = document.querySelector(`#determinate-progress`); e && setInterval(() => { e.value >= 100 ? (e.value = 10) : (e.value += 10); }, 3e3);</script>Variants
Use the variant prop to swap the progress bar track surface for better contrast on different backgrounds.
---import { Progress } from "@opui/astro"---
<Progress value="25" max="100" variant="default" /><Progress value="50" max="100" variant="filled" /><Progress value="75" max="100" variant="tonal" /><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, (number & string[]) | - | 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>. |
Other attributes 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%; } }}