TopProgress

The indeterminate bar a route wears while it fetches. Sweeps edge to edge from the seam, and holds a filled track rather than vanishing when motion is off.

Install

$ npx shadcn@latest add wisp.pouriah.com/r/top-progress.json
Loader · CSSindeterminate
route fetching · indeterminate

TopProgressesc or double-click to exit full screendouble-tap to exit

loaders/top-progress.tsx
"use client";

import * as React from "react";
import { cx } from "@pouriahlabs/wisp-ui";

/**
 * TopProgress — the indeterminate bar a route wears while it fetches.
 *
 * A thin track with a seam-coloured comet sweeping edge to edge: the loader you
 * pin to the top of a layout so a navigation has a heartbeat before its content
 * arrives. It reports nothing about how far along the work is — that is the
 * honest shape when you don't know — only that work is happening.
 *
 * The sweep is a compositor transform, so it never touches layout, and under
 * reduced motion it holds a filled track rather than a bar parked off-screen: a
 * still frame that still reads as loading.
 */

export interface TopProgressProps extends React.HTMLAttributes<HTMLDivElement> {
  /** Token for the comet's leading edge. */
  fromToken?: string;
  /** Token for its trailing edge — the second half of the seam. */
  toToken?: string;
  /** Track thickness, as any CSS length. */
  height?: string;
  /** Seconds per sweep. */
  duration?: number;
  /** Accessible status text announced while the bar is on screen. */
  label?: string;
}

export function TopProgress({
  fromToken = "--wisp",
  toToken = "--lantern",
  height = "2px",
  duration = 1.15,
  label = "Loading",
  className,
  style,
  ...props
}: TopProgressProps) {
  return (
    <div
      className={cx("wisp-progress", className)}
      role="status"
      aria-label={label}
      style={
        {
          "--wisp-progress-from": `var(${fromToken})`,
          "--wisp-progress-to": `var(${toToken})`,
          "--wisp-progress-height": height,
          "--wisp-progress-duration": `${duration}s`,
          ...style,
        } as React.CSSProperties
      }
      {...props}
    >
      <span className="wisp-progress-bar" aria-hidden />
    </div>
  );
}

Certified against the contract