Fortschritt

Nimm einen bestimmten Balken, wann immer du weißt, wie viel noch fehlt — nur er sagt der Leserin überhaupt etwas. Lass value weg, und der Balken animiert stattdessen, was „arbeitet noch“ heißt und sonst nichts.

Bestimmt

stack({ gap: 'lg' },
  progress({ value: 25 }),
  progress({ value: 60 }),
  progress({ value: 100 }),
)

Unbestimmt

progress()

Ein Balken ohne label bekommt aria-hidden — eine progressbar-Rolle ohne zugänglichen Namen sagt einem Screenreader nichts, ein unbeschrifteter Balken gilt also als Dekoration. Beschrifte alles, dem eine Leserin folgen soll.

Beschriftungen

Ein Label benennt, was passiert; showValue ergänzt rechts den Prozentwert.

Seiten werden gerendert72%
Bilder werden optimiert50%
Warte auf das Deployment
stack({ gap: 'lg' },
  progress({ value: 72, label: 'Seiten werden gerendert', showValue: true }),
  progress({ value: 30, max: 60, label: 'Bilder werden optimiert', showValue: true }),
  progress({ label: 'Warte auf das Deployment' }),
)

Farben und Höhe

Bestanden80%
Eingeschränkt45%
Fehlerhaft20%
stack({ gap: 'lg' },
  progress({ value: 80, color: 'success', label: 'Bestanden', showValue: true }),
  progress({ value: 45, color: 'warning', label: 'Eingeschränkt', showValue: true }),
  progress({ value: 20, color: 'danger', label: 'Fehlerhaft', showValue: true }),
  progress({ value: 60, color: 'neutral', height: 'xs' }),
  progress({ value: 60, color: 'primary', height: '1rem' }),
)

Eine andere Skala als 100

max lässt dich die rohen Zahlen übergeben — gebaute Seiten von Seiten insgesamt — statt vorher einen Prozentwert auszurechnen.

118 von 169 Seiten70%
progress({ value: 118, max: 169, label: '118 von 169 Seiten', showValue: true })

Sie vom Browser aus bewegen

Ein Balken ist serverseitig gerendertes HTML: der Prozentwert ist eine Custom Property auf der Füllung und eine Zahl in aria-valuenow, und nichts auf der Seite ändert von sich aus eines von beiden. Gib dem Balken eine id, und setProgress bewegt beides zusammen — die Füllung, den angesagten Wert und den Prozentwert neben der Beschriftung.

import { setProgress } from 'sitelo/ui/client'

const request = new XMLHttpRequest()

request.upload.addEventListener('progress', (event) => {
  setProgress('upload', event.loaded, { max: event.total })
})

Das Maximum wird gemerkt, spätere Aufrufe sind also nur noch ein Wert. Oder erreiche das Modul so, wie es die Komponenten tun, und lass das Bundle ganz weg:

button({ onclick: "import('/su/progress.js').then(m=>m.set('upload',100))" }, 'Fertig')

Mit null — oder allem, was keine endliche Zahl ist — geht der Balken zurück in die unbestimmte Animation, sodass Arbeit, die keine Zahlen mehr liefert, kein Sonderfall sein muss. getProgress() liest den aktuellen Wert wieder aus, auf der eigenen Skala des Balkens.

Probier es aus

Diese Seite lädt das Runtime, die Buttons unten bewegen den Balken also wirklich.

Wird hochgeladen0%
stack({ gap: 'md' },
  progress({ id: 'demo-progress', value: 0, label: 'Wird hochgeladen', showValue: true }),
  stack({ direction: 'row', gap: 'sm', wrap: true },
    button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',0))" }, 'Zurücksetzen'),
    button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',35))" }, '35%'),
    button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',80))" }, '80%'),
    button({ size: 'sm', variant: 'outline', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',100))" }, 'Fertig'),
    button({ size: 'sm', variant: 'ghost', onclick: "import('/su/progress.js').then(m=>m.set('demo-progress',null))" }, 'Unbekannt'),
  ),
)

Ein unbeschrifteter Balken bewegt sich ebenfalls, bleibt aber aria-hidden — er wurde mit Absicht ohne Namen gerendert, und ihm jetzt einen Wert anzusagen würde eine namenlose progressbar in den Accessibility-Baum stellen.

Spinner

Es gibt keine Spinner-Komponente — der Spinner ist ein Icon, und spin ist das, was es dreht. Wie jedes Icon wird es in em bemessen und passt so zu dem Text neben ihm, ohne eine Größe genannt zu bekommen.

stack({ direction: 'row', gap: 'lg', align: 'center' },
  icon('spinner', { spin: true, size: 'sm' }),
  icon('spinner', { spin: true }),
  icon('spinner', { spin: true, size: 'lg' }),
)

Der Spinner im Zusammenhang

Gib einem allein stehenden Spinner ein label, damit er angesagt wird. Einer in einem Button braucht keines — der Button sagt schon, was er tut.

Hole den letzten Build…

stack({ gap: 'md' },
  stack({ direction: 'row', gap: 'sm', align: 'center' },
    icon('spinner', { spin: true, label: 'Lädt' }),
    text({ variant: 'small', tone: 'muted' }, 'Hole den letzten Build…'),
  ),
  stack({ direction: 'row', gap: 'sm' },
    button({ loading: true }, 'Deployt'),
    button({ variant: 'outline', loading: true }, 'Prüfe Links'),
  ),
)

Props

progress() — auch als progressBar exportiert:

PropTypStandardBeschreibung
valuenumber—Wie weit es ist. Weglassen für die unbestimmte Animation.
maxnumber100Welcher Wert als fertig zählt.
color'primary' | 'neutral' | 'success' | 'warning' | 'danger''primary'Füllfarbe.
labelChild—Text über dem Balken; zugleich sein zugänglicher Name.
showValuebooleanfalseDen Prozentwert neben dem Label zeigen.
heightSpace'0.5rem'Dicke des Balkens.

setProgress() aus sitelo/ui/client:

PropTypStandardBeschreibung
targetElement | string—Der Balken oder die id eines Balkens. Trägt kein Element diese id, wird sie als Selektor versucht.
valuenumber | null—Wohin er soll. null gibt ihn zurück an die unbestimmte Animation.
options.maxnumber100Was als fertig zählt. Wird für die folgenden Aufrufe gemerkt.

Der Spinner hat keine eigenen Props — er ist icon('spinner', { spin: true }) und nimmt, was icon() nimmt.