All loaders

CSS / SVG · 3.2 KB gzip

Progress Bar

A compact linear indicator with indeterminate flow and smoothly updated determinate progress.

progresslinearinlinedeterminate
Interactive preview

Usage

Download HTML

Packages are @vikast908/core and @vikast908/loaders. Prefer 0.1.1+ (0.1.0 loaders is broken on npm).

npm install @vikast908/loaders@0.1.1 @vikast908/core@0.1.1
import '@vikast908/loaders/progress-bar';

<orbux-progress-bar state="thinking"></orbux-progress-bar>

Browser-only alternative: Download HTML (self-contained) or load the hosted ESM bundle:

<script type="module" src="http://localhost:4321/orbux/progress-bar.js"></script>

<orbux-progress-bar state="thinking"></orbux-progress-bar>

Component source progress-bar.ts

import { OrbuxElement } from '@vikast908/core';

const STYLES = /* css */ `
:host{inline-size:var(--orbux-width,var(--orbux-size,160px));block-size:var(--orbux-height,8px);--_p:0}
.track{position:relative;overflow:hidden;inline-size:100%;block-size:100%;min-block-size:4px;border-radius:999px;background:color-mix(in srgb,var(--orbux-color,#6366f1) 16%,transparent)}
.fill{position:absolute;inset:0;transform-origin:left center;background:var(--orbux-color-progress,var(--orbux-color,#6366f1));transform:scaleX(var(--_p));transition:transform 120ms ease-out;border-radius:inherit}
:host(:not([data-determinate])) .fill{inline-size:42%;transform:translateX(-110%);animation:orbux-bar-flow calc(1.15s * var(--orbux-speed-scale)) ease-in-out infinite}
@keyframes orbux-bar-flow{to{transform:translateX(340%)}}
:host([data-state="streaming"]:not([data-determinate])) .fill{animation-duration:calc(.72s * var(--orbux-speed-scale))}
:host([data-state="tool-calling"]) .track{border-radius:2px;background:repeating-linear-gradient(90deg,color-mix(in srgb,var(--orbux-color,#6366f1) 18%,transparent) 0 10px,transparent 10px 13px)}
:host([data-state="idle"]) .fill{animation-play-state:paused;opacity:.4}
:host([data-state="waiting"]) .fill{animation-play-state:paused;opacity:.75;inline-size:28%}
:host([data-state="done"]) .fill{animation:none;inline-size:100%;transform:none;background:var(--orbux-color-success,#22c55e)}
:host([data-state="error"]) .fill{animation:orbux-bar-error 200ms ease-out 1;inline-size:100%;transform:none;background:var(--orbux-color-error,#ef4444)}
@keyframes orbux-bar-error{35%{translate:-2%}70%{translate:2%}}
:host([data-settled="true"]) .fill{animation:none}
:host([data-paused="true"]) .fill{animation-play-state:paused}
:host([data-reduced-motion="true"]:not([data-determinate])) .fill{animation:none;transform:none;inline-size:var(--_static,38%)}
:host([data-reduced-motion="true"][data-state="streaming"]) {--_static:72%}
:host([data-reduced-motion="true"][data-state="tool-calling"]) {--_static:55%}
:host([data-reduced-motion="true"][data-state="waiting"]) {--_static:24%}
`;

export class OrbuxProgressBar extends OrbuxElement {
  protected build(): void {
    const style = document.createElement('style');
    style.textContent = STYLES;
    const track = document.createElement('span');
    track.className = 'track';
    track.setAttribute('part', 'track');
    const fill = document.createElement('span');
    fill.className = 'fill';
    fill.setAttribute('part', 'fill');
    track.append(fill);
    this.root.append(style, track);
  }

  protected onProgressChange(progress: number | null): void {
    this.toggleAttribute('data-determinate', progress != null);
    this.style.setProperty('--_p', String(progress ?? 0));
  }
}

if (typeof customElements !== 'undefined' && !customElements.get('orbux-progress-bar')) {
  customElements.define('orbux-progress-bar', OrbuxProgressBar);
}

declare global {
  interface HTMLElementTagNameMap {
    'orbux-progress-bar': OrbuxProgressBar;
  }
}

Depends on @vikast908/core. Paste the source, add the base element, and set state from your agent code.

Attributes & properties

NameTypeDescription
stateAgentState idle · thinking · streaming · tool-calling · waiting · done · error
progressnumber (0 to 1) Determinate progress from 0 to 1.
sizeCSS lengthOverall square size.
--orbux-widthCSS lengthOptional inline-size override.
--orbux-heightCSS lengthOptional block-size override.
speednumberAnimation speed multiplier (1 = default).
labelstringAccessible label (defaults per state).
pausedbooleanFreeze the animation.

Respects prefers-reduced-motion, exposes status/progressbar semantics with a live label, and auto-pauses (sets data-paused) when offscreen or the tab is hidden.