Svelte 5 component · fractalsvelte-ui · Display
Progress
A linear horizontal progress indicator communicating the completion status of ongoing processes. Supports determinate values, animated stripes, and an indeterminate activity mode.
Install
Progress is a Svelte 5 progress component in @fractaldesign/fractalsvelte-ui. It works in SvelteKit and in any Svelte 5 app.
pnpm add @fractaldesign/fractalsvelte-uiImport
import { Progress } from '@fractaldesign/fractalsvelte-ui';Usage
<Progress value={0} max={100} size={'md'} />Props
Also accepts every attribute of HTMLAttributes, spread onto
the root element.
| Name | Type | Default |
|---|---|---|
value | number | 0 |
max | number | 100 |
size | Size 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' |
intent | ProgressIntent | 'primary' |
indeterminate | boolean | false |
striped | boolean | false |
animated | boolean | false |
showValue | boolean | false |
label | string | — |
class | string | '' |
Source
Show the Progress.svelte source
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import type { Size, Intent } from '../../types';
export type ProgressIntent = Intent | 'primary';
interface Props extends HTMLAttributes<HTMLDivElement> {
value?: number;
max?: number;
size?: Size;
intent?: ProgressIntent;
indeterminate?: boolean;
striped?: boolean;
animated?: boolean;
showValue?: boolean;
label?: string;
class?: string;
}
let {
value = 0,
max = 100,
size = 'md',
intent = 'primary',
indeterminate = false,
striped = false,
animated = false,
showValue = false,
label,
class: className = '',
...restProps
}: Props = $props();
const percentage = $derived(
indeterminate ? 0 : Math.min(100, Math.max(0, (value / (max || 100)) * 100))
);
</script>
<div
class="f-progress-wrapper {className}"
data-size={size}
data-intent={intent}
{...restProps}
>
{#if label || showValue}
<div class="f-progress-header">
{#if label}
<span class="f-progress-label">{label}</span>
{/if}
{#if showValue && !indeterminate}
<span class="f-progress-value">{Math.round(percentage)}%</span>
{/if}
</div>
{/if}
<div
role="progressbar"
aria-valuenow={indeterminate ? undefined : Math.round(percentage)}
aria-valuemin={0}
aria-valuemax={max}
aria-label={label}
class="f-progress-track"
>
<div
class="f-progress-bar"
data-indeterminate={indeterminate ? '' : undefined}
data-striped={striped ? '' : undefined}
data-animated={animated ? '' : undefined}
style={indeterminate ? undefined : `width: ${percentage}%`}
></div>
</div>
</div>
<style>
@layer fractalsvelte-ui.components {
.f-progress-wrapper {
width: 100%;
display: flex;
flex-direction: column;
gap: var(--f-space-2xs);
box-sizing: border-box;
font-family: inherit;
}
.f-progress-header {
display: flex;
align-items: center;
justify-content: space-between;
font-size: var(--f-text-xs);
font-weight: 500;
color: var(--f-text-muted);
}
.f-progress-track {
width: 100%;
background: var(--f-sunken);
border-radius: var(--f-radius-full);
overflow: hidden;
position: relative;
}
.f-progress-bar {
height: 100%;
border-radius: var(--f-radius-full);
transition: width var(--f-duration-normal) var(--f-ease);
}
/* Sizes */
.f-progress-wrapper[data-size='xs'] .f-progress-track {
height: 4px;
}
.f-progress-wrapper[data-size='sm'] .f-progress-track {
height: 6px;
}
.f-progress-wrapper[data-size='md'] .f-progress-track {
height: 8px;
}
.f-progress-wrapper[data-size='lg'] .f-progress-track {
height: 12px;
}
.f-progress-wrapper[data-size='xl'] .f-progress-track {
height: 16px;
}
/* Intents */
.f-progress-wrapper[data-intent='primary'] .f-progress-bar {
background-color: var(--f-primary);
}
.f-progress-wrapper[data-intent='info'] .f-progress-bar {
background-color: var(--f-info);
}
.f-progress-wrapper[data-intent='success'] .f-progress-bar {
background-color: var(--f-success);
}
.f-progress-wrapper[data-intent='warning'] .f-progress-bar {
background-color: var(--f-warning);
}
.f-progress-wrapper[data-intent='danger'] .f-progress-bar {
background-color: var(--f-danger);
}
/* Striped */
.f-progress-bar[data-striped] {
background-image: linear-gradient(
45deg,
rgba(255, 255, 255, 0.15) 25%,
transparent 25%,
transparent 50%,
rgba(255, 255, 255, 0.15) 50%,
rgba(255, 255, 255, 0.15) 75%,
transparent 75%,
transparent
);
background-size: 1rem 1rem;
}
.f-progress-bar[data-animated] {
animation: f-progress-stripes 1s linear infinite;
}
@keyframes f-progress-stripes {
from {
background-position: 1rem 0;
}
to {
background-position: 0 0;
}
}
/* Indeterminate */
.f-progress-bar[data-indeterminate] {
width: 40% !important;
position: absolute;
top: 0;
bottom: 0;
animation: f-progress-indeterminate 1.5s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
}
@keyframes f-progress-indeterminate {
0% {
left: -40%;
width: 30%;
}
50% {
left: 20%;
width: 60%;
}
100% {
left: 100%;
width: 30%;
}
}
}
</style>Related components
SizeReadout A design-tool inspired live dimension tag and overlay chip showing width × height measurements, item counts,…Skeleton An animated placeholder mimicking content geometry while data loads.Sparkline A lightweight inline SVG micro-chart displaying trend trajectories with optional gradient fill and smoothed…Spinner A circular vector loading indicator for asynchronous operations and busy states.StatCard A dashboard metric card presenting a key performance indicator.Tag An interactive label chip designed for categorization, selection, and multi-value inputs.