# Progress

Determinate and indeterminate progress bar.

- Package: `@mielui/svelte`
- Component version: `1.0.0`
- Depends on Mielui components: _internal/utils
- Shared utilities: components/_internal/theme-changes, components/_internal/motion-loop, utils.cn, transition

## Install

~~~~sh
pnpm dlx @mielui/svelte add progress
~~~~

## API

This reference is generated at build time from the component manifest, public `index.ts`, and documentation examples below. Changes to those source files are reflected here in the published Markdown. Standard Svelte and HTML attributes accepted by the exported prop types are supported.


### Progress

| Prop | Type | Default | Required | Bindable | Description |
| --- | --- | --- | --- | --- | --- |
| value | number \| undefined | 0 | No | No | Completed amount. |
| max | number \| undefined | 100 | No | No | Amount that counts as complete. |
| indeterminate | boolean \| undefined | false | No | No | Shows activity when the amount is not known. |

Also accepts the native HTML attributes and events listed in the rendered API reference.

### Public types

~~~~ts
import type { HTMLAttributes } from 'svelte/elements';
import Progress from './progress.svelte';

export type ProgressProps = {
    /** Completed amount. */
    value?: number;
    /** Amount that counts as complete. */
    max?: number;
    /** Shows activity when the amount is not known. */
    indeterminate?: boolean;
} & Omit<
    HTMLAttributes<HTMLDivElement>,
    'children' | 'role' | 'aria-valuemin' | 'aria-valuemax' | 'aria-valuenow'
>;

export { Progress };
export default Progress;
~~~~

## Examples

### Determinate

~~~~svelte
<script lang="ts">
    import { Progress } from '@mielui/svelte/components/progress';
</script>

<div class="w-full max-w-md">
    <Progress aria-label="Upload progress" value={45} />
</div>
~~~~

### Indeterminate

~~~~svelte
<script lang="ts">
    import { Button } from '@mielui/svelte/components/button';
    import { Progress } from '@mielui/svelte/components/progress';

    let pending = $state(true);
</script>

<div class="flex w-full max-w-md flex-col gap-4">
    <Progress aria-label="Sample request" indeterminate={pending} value={pending ? 0 : 100} />
    <div class="flex items-center justify-between gap-4">
        <p class="m-0 text-sm text-foreground-muted" role="status">
            {pending ? 'Waiting for a response' : 'Response received'}
        </p>
        <Button
            variant="secondary"
            onclick={() => {
            pending = !pending;
        }}
        >
            {pending ? 'Complete request' : 'Start again'}
        </Button>
    </div>
</div>
~~~~

### Upload

~~~~svelte
<script lang="ts">
    import { numberShuffle } from '@mielui/svelte/actions/number-shuffle';
    import { Button } from '@mielui/svelte/components/button';
    import { Progress } from '@mielui/svelte/components/progress';
    import { onDestroy } from 'svelte';

    let value = $state(0);
    let running = $state(false);
    let timer: ReturnType<typeof setInterval> | undefined;
    const status = $derived(
        value === 100 ? 'Upload complete' : running ? 'Uploading release.zip' : 'Ready to upload'
    );

    function start() {
        clearInterval(timer);
        value = 0;
        running = true;
        timer = setInterval(() => {
            value = Math.min(100, value + 10);
            if (value === 100) {
                clearInterval(timer);
                running = false;
            }
        }, 240);
    }

    function cancel() {
        clearInterval(timer);
        running = false;
        value = 0;
    }

    onDestroy(() => {
        clearInterval(timer);
    });
</script>

<div class="flex w-full max-w-md flex-col gap-4">
    <div class="flex items-center justify-between gap-3 text-sm">
        <span role="status">{status}</span>
        <span
            class="tabular-nums text-foreground-muted"
            use:numberShuffle={{ value, format: (next) => `${next}%` }}
        >
            {`${value}%`}
        </span>
    </div>
    <Progress aria-label="Release archive upload" {value} />
    <div class="flex gap-2">
        <Button onclick={start} disabled={running}>
            {value === 100 ? 'Upload again' : 'Start upload'}
        </Button>
        {#if running}
            <Button variant="secondary" onclick={cancel}>Cancel</Button>
        {/if}
    </div>
    <p class="text-xs text-foreground-muted">Simulated transfer. No files leave your device.</p>
</div>
~~~~

### With Label

~~~~svelte
<script lang="ts">
    import { Progress } from '@mielui/svelte/components/progress';
</script>

<div class="w-full max-w-md flex flex-col gap-2">
    <div class="flex items-center justify-between text-sm text-foreground-muted">
        <span>Uploading…</span>
        <span>72%</span>
    </div>
    <Progress aria-label="Upload progress" value={72} />
</div>
~~~~

For the rendered reference, visit [/docs/components/progress](/docs/components/progress).
