Skip to content
Sign in
EffectsScanline loaderMenu

Scanline loaderPro

A framed placeholder with faint 2 px scanlines and one soft band passing over it, for a frame that is being rendered. CSS only.

ProA frame being rendered: one soft scan band over faint scanlines, with a caption.

Installation

$ pnpm dlx shadcn@latest add @chatcn-pro/scanline-loader

Usage

tsx
import { ScanlineLoader } from "@/components/ui/chatcn/pro/scanline-loader"

<ScanlineLoader aspectRatio="16 / 9" label="Rendering frame" />

Give it the aspect ratio of the frame that will replace it, so nothing moves when the result lands. children sit on top for a caption or a progress readout; with children the caption speaks for itself and the frame drops its image role.

Examples

Shapes and states

ProSquare and portrait slots, no scanlines, an upward pass, paused and the reduced motion frame.

Pending timing

As a pending state, a loader never shows in the first 300 ms, and once shown it stays at least 400 ms so it never flashes. useDelayedPresence from the free thinking-indicator does both.

Props

PropTypeNotes
aspectRatiostring | numberCSS aspect ratio. Default "4 / 3"
linesbooleanDraws the scanlines. Default true
direction"down" | "up"Which way the band travels. Default down
speednumberLoop speed multiplier. Default 1
pausedbooleanFreezes the loop
stillbooleanDraws the reduced motion frame
labelstringAccessible name. Default "Loading"; empty hides it

Motion

  • One pass takes 2.6 s: the band crosses in the first 72% with an in-out curve, then rests out of view so each pass reads as one scan. It moves by its own height, so the pass looks the same at every size.
  • Under reduced motion the movement stops on one still frame and the whole loader breathes in opacity, 1 to 0.55 over 1.4 s. still draws that frame on demand; paused freezes the loop where it is.
  • Animates only transform, opacity and clip-path. No JavaScript runs per frame.

Accessibility

  • The frame is role="img" named by label, "Loading" by default. Next to a visible label, pass label="" and it hides from assistive tech.
  • Announce the outcome, not the wait: put a polite live region on the result instead of on the loader.
  • Under forced-colors the shapes draw in CanvasText.