Feedback
Progress
A linear progress bar with determinate values, an indeterminate animation and an accessible label.
<script>
import { Progress } from "@codeatlasdev/ui";
</script>
<Progress value={60} label="Upload progress" />
<Progress indeterminate label="Loading" />
Renders role="progressbar" with aria-valuenow, aria-valuemin and aria-valuemax. Always pass label so screen readers know what is progressing. The indeterminate state omits aria-valuenow.
Determinate
An explicit value from 0 to max (100 by default).
Code
<script lang="ts">
import { Progress } from '@codeatlasdev/ui';
</script>
<div class="col">
{#each [25, 50, 75, 100] as v}
<div class="row">
<span class="label">{v}%</span>
<Progress value={v} label="{v} percent" />
</div>
{/each}
</div>
<style>
.col { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 480px; }
.row { display: flex; align-items: center; gap: 14px; }
.label {
font-size: var(--ca-font-size-caption);
font-family: var(--ca-font-mono);
color: var(--ca-text-secondary);
min-width: 64px;
flex-shrink: 0;
text-align: right;
}
</style>
Indeterminate
Use when progress cannot be determined.
Code
<script lang="ts">
import { Progress } from '@codeatlasdev/ui';
</script>
<div class="col">
<div class="row">
<span class="label">Loading</span>
<Progress indeterminate label="Loading content" />
</div>
<div class="row">
<span class="label">Syncing</span>
<Progress indeterminate label="Syncing data" />
</div>
</div>
<style>
.col { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 480px; }
.row { display: flex; align-items: center; gap: 14px; }
.label {
font-size: var(--ca-font-size-caption);
font-family: var(--ca-font-mono);
color: var(--ca-text-secondary);
min-width: 64px;
flex-shrink: 0;
text-align: right;
}
</style>
Animated
Start a simulated upload.
Code
<script lang="ts">
import { Progress, Button } from '@codeatlasdev/ui';
import { onDestroy } from 'svelte';
let value = $state(0);
let running = $state(false);
let timer: ReturnType<typeof setInterval> | undefined;
function start() {
if (running) return;
value = 0;
running = true;
timer = setInterval(() => {
value = Math.min(100, value + 5);
if (value >= 100) {
clearInterval(timer);
running = false;
}
}, 100);
}
onDestroy(() => clearInterval(timer));
</script>
<div class="col">
<div class="row">
<span class="label">{value}%</span>
<Progress {value} label="Upload progress" />
</div>
<Button variant="outlined" size="sm" disabled={running} onclick={start}>
{running ? 'Uploading…' : 'Start upload'}
</Button>
</div>
<style>
.col { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 480px; }
.row { display: flex; align-items: center; gap: 14px; }
.label {
font-size: var(--ca-font-size-caption);
font-family: var(--ca-font-mono);
color: var(--ca-text-secondary);
min-width: 64px;
flex-shrink: 0;
text-align: right;
}
</style>
Props
| Prop | Type | Default | Description |
|---|
value | number | 0 | Current progress value. |
max | number | 100 | Maximum value. The fill is clamped between 0 and 100%. |
indeterminate | boolean | false | Plays the shimmer animation when progress is unknown. |
label | string | – | Accessible aria-label for screen readers. |
class | string | '' | Extra CSS classes. |