Loading State Zoo

Documentation

Patterns that stay smooth.

Every pattern ships as a web component with a React wrapper, plus a plain-CSS theme. One install, 26 compositor-friendly animations.

Installation

npm install loading-state-zoo

Three entry points, same package. Importing any of them auto-registers every custom element exactly once — never call defineAll() yourself.

PurposeImport
Framework-agnostic web componentsimport "loading-state-zoo";
React componentsimport { BouncingDots } from "loading-state-zoo/react";
Plain CSS + hand-written markuplink "loading-state-zoo/theme.css"

Usage

Drop a tag or component anywhere. Web components are server-render safe — on the server the tags stay inert and never throw.

<!-- Plain HTML / any framework -->
<lz-wave-dots size="12" color="#0a84ff"></lz-wave-dots>

<!-- Or React -->
import { WaveDots, ArcSpinner } from "loading-state-zoo/react";
export default () => <WaveDots size={12} color="#0a84ff" />;

Multi-word attributes are camelCased in React: stroke-width strokeWidth, track-colortrackColor, bar-widthbarWidth, color-weak colorWeak.

Theming

Styles live inside each element‘s shadow DOM, so you theme with CSS variables on the host or any ancestor — never by reaching in.

VariableDefaultPurpose
--lz-color#f5f5f7Foreground color on every pattern
--lz-accent#0a84ffAccent color (morphing square, progress bar)
--lz-speed1Duration multiplier (0.5 = faster, 2 = slower)
--lz-stroke4pxRing stroke width
--lz-surface#1c1c1eTrack / skeleton background
--lz-trackrgba(255,255,255,0.15)Ring and bar track color
<!-- Theme a single element -->
<lz-arc-spinner style="--lz-color:#0a84ff; --lz-speed:0.8"></lz-arc-spinner>

<!-- React: pass vars via style -->
<ArcSpinner style={{ "--lz-color": "#0a84ff", "--lz-speed": 0.8 } as React.CSSProperties} />

The patterns

26 patterns in five families. All animate only transform and opacity, so they stay at 60fps on phones.

Dots

BouncingDots

lz-bouncing-dots

Three round dots that hop up and down with a stagger. loading a feed · small section refresh

AttributeTypeDefault
sizenumber8
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-bounce-10pxDot hop height
<lz-bouncing-dots size="8"></lz-bouncing-dots>
import { BouncingDots } from "loading-state-zoo/react";

<BouncingDots size={8} />

TypingDots

lz-typing-dots

Three dots pulsing in a typing rhythm. chat · messaging · typing indicator

AttributeTypeDefault
sizenumber8
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-typing-min0.35Resting dot scale
--lz-typing-peak1.15Peak dot scale
<lz-typing-dots size="8"></lz-typing-dots>
import { TypingDots } from "loading-state-zoo/react";

<TypingDots size={8} />

WaveDots

lz-wave-dots

Four dots swelling across like a wave. refresh · sync in progress

AttributeTypeDefault
sizenumber8
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-wave-min0.35Resting dot scale
--lz-wave-peak1.1Peak dot scale
<lz-wave-dots size="8"></lz-wave-dots>
import { WaveDots } from "loading-state-zoo/react";

<WaveDots size={8} />

HelixDots

lz-helix-dots

A row of dots bobbing like a travelling wave (helix). data processing · playful waits

AttributeTypeDefault
sizenumber6
countnumber10
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-helix-12pxDot bob distance
<lz-helix-dots size="6" count="10"></lz-helix-dots>
import { HelixDots } from "loading-state-zoo/react";

<HelixDots size={6} count={10} />

DotGridWave

lz-dot-grid-wave

A grid of dots rippling outward from the top-left corner. dashboards · brick layouts · empty panels

AttributeTypeDefault
sizenumber6
rowsnumber4
colsnumber5
gapnumber12
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-grid-min0.3Resting dot scale
--lz-grid-fade0.15Resting dot opacity
<lz-dot-grid-wave size="6" rows="4" cols="5" gap="12"></lz-dot-grid-wave>
import { DotGridWave } from "loading-state-zoo/react";

<DotGridWave size={6} rows={4} cols={5} gap={12} />

Ellipsis

lz-ellipsis

Three periods appearing in a typing rhythm. chat · messaging · text queues

AttributeTypeDefault
sizenumber8
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-ellipsis-min0.8Resting dot scale
--lz-ellipsis-fade0.15Resting dot opacity
<lz-ellipsis size="8"></lz-ellipsis>
import { Ellipsis } from "loading-state-zoo/react";

<Ellipsis size={8} />

Spinners

ArcSpinner

lz-arc-spinner

One spinning arc ring (classic circular loader). any circular wait

AttributeTypeDefault
sizenumber44
strokeWidth (web: stroke-width)number4
colorstring#f5f5f7
speednumber1
<lz-arc-spinner size="44" stroke-width="4"></lz-arc-spinner>
import { ArcSpinner } from "loading-state-zoo/react";

<ArcSpinner size={44} strokeWidth={4} />

MaterialDoubleArc

lz-material-double-arc

Two arcs spinning in opposite directions (Material look). android-style apps · processing

AttributeTypeDefault
sizenumber44
strokeWidth (web: stroke-width)number4
colorstring#f5f5f7
colorWeak (web: color-weak)string95% tint of color
speednumber1
<lz-material-double-arc size="44" stroke-width="4"></lz-material-double-arc>
import { MaterialDoubleArc } from "loading-state-zoo/react";

<MaterialDoubleArc size={44} strokeWidth={4} />

ScanSweep

lz-scan-sweep

Concentric rings with crosshair ticks, a counter-rotating dial and a sweeping radar beam. scanning · searching · syncing

AttributeTypeDefault
sizenumber44
colorstring#f5f5f7
colorWeak (web: color-weak)string80% tint of color
colorSweep (web: color-sweep)string8% tint of color
speednumber1
<lz-scan-sweep size="44"></lz-scan-sweep>
import { ScanSweep } from "loading-state-zoo/react";

<ScanSweep size={44} />

OrbitDots

lz-orbit-dots

Three dots gliding around an invisible circle. light floaty waits

AttributeTypeDefault
sizenumber44
colorstring#f5f5f7
speednumber1
<lz-orbit-dots size="44"></lz-orbit-dots>
import { OrbitDots } from "loading-state-zoo/react";

<OrbitDots size={44} />

OrbitRingDots

lz-orbit-ring-dots

Eight dots around a ring chasing each other with fading opacity. elegant circular waits · brand moments

AttributeTypeDefault
sizenumber44
dotSize (web: dot-size)number0.18 x size
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-orbit-fade0.12Resting dot opacity
<lz-orbit-ring-dots size="44" dot-size="7.92"></lz-orbit-ring-dots>
import { OrbitRingDots } from "loading-state-zoo/react";

<OrbitRingDots size={44} dotSize={7.92} />

Sonar

lz-sonar

A pulsing core emitting expanding sonar rings. radar pings · location detection · motion waits

AttributeTypeDefault
sizenumber44
countnumber3
accentstring#0a84ff
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-sonar-fade0.9Ring start opacity
<lz-sonar size="44" count="3"></lz-sonar>
import { Sonar } from "loading-state-zoo/react";

<Sonar size={44} count={3} />

Shapes

Eyes

lz-eyes

Two cartoon eyes that look side to side and blink. fun apps · kids' stuff · watching moments

AttributeTypeDefault
sizenumber44
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-gaze-from-3pxPupil start offset
--lz-gaze-to3pxPupil end offset
--lz-blink0.08Blink closure scale
<lz-eyes size="44"></lz-eyes>
import { Eyes } from "loading-state-zoo/react";

<Eyes size={44} />

MorphingSquare

lz-morphing-square

A glowing square that swells, rounds and spins. modern splash states · brand colors

AttributeTypeDefault
sizenumber44
accentstring#0a84ff
speednumber1
VariableDefaultPurpose
--lz-morph0.72Smallest scale
--lz-morph-radius17%Corner roundness at peak
<lz-morphing-square size="44"></lz-morphing-square>
import { MorphingSquare } from "loading-state-zoo/react";

<MorphingSquare size={44} />

BreathingPulse

lz-breathing-pulse

A soft circle that gently grows and shrinks. subtle alive waits · background states

AttributeTypeDefault
sizenumber36
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-breath1.14Growth scale
<lz-breathing-pulse size="36"></lz-breathing-pulse>
import { BreathingPulse } from "loading-state-zoo/react";

<BreathingPulse size={36} />

Bars & rings

Equalizer

lz-equalizer

Four bars dancing like a music equalizer. audio · music · waveform

AttributeTypeDefault
sizenumber22
barWidth (web: bar-width)number3
gapnumber3
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-eq-min0.3Shortest bar scale
<lz-equalizer size="22" bar-width="3" gap="3"></lz-equalizer>
import { Equalizer } from "loading-state-zoo/react";

<Equalizer size={22} barWidth={3} gap={3} />

ProgressRing

lz-progress-ring

A ring that fills to a driven percentage. Static — set percent. uploads · downloads · known percent tasks

AttributeTypeDefault
sizenumber44
strokeWidth (web: stroke-width)number4
percentnumber0
colorstring#f5f5f7
trackColor (web: track-color)stringrgba(255,255,255,0.15)
speednumber1
<lz-progress-ring size="44" stroke-width="4" percent="0"></lz-progress-ring>
import { ProgressRing } from "loading-state-zoo/react";

<ProgressRing size={44} strokeWidth={4} percent={0} />

ProgressBar

lz-progress-bar

A determinate linear progress bar filling to a driven percentage. uploads · downloads · known percent tasks

AttributeTypeDefault
widthnumber160
heightnumber6
percentnumber0
colorstring#f5f5f7
trackColor (web: track-color)stringrgba(255,255,255,0.15)
speednumber1
<lz-progress-bar width="160" height="6" percent="0"></lz-progress-bar>
import { ProgressBar } from "loading-state-zoo/react";

<ProgressBar width={160} height={6} percent={0} />

IndeterminateProgressBar

lz-indeterminate-progress-bar

A bar with a slider sliding back and forth (unknown progress). long unknown tasks

AttributeTypeDefault
widthnumber160
heightnumber6
accentstring#0a84ff
trackColor (web: track-color)string#1c1c1e
speednumber1
VariableDefaultPurpose
--lz-slide-from-100%Slider start
--lz-slide-to300%Slider end
<lz-indeterminate-progress-bar width="160" height="6"></lz-indeterminate-progress-bar>
import { IndeterminateProgressBar } from "loading-state-zoo/react";

<IndeterminateProgressBar width={160} height={6} />

ActivityRings

lz-activity-rings

Three Apple Watch-style activity rings spinning at different speeds and directions. fitness apps · health dashboards · workout sync

AttributeTypeDefault
sizenumber44
accentstring#fa114f
colorstring#30d158
colorWeak (web: color-weak)string#32d7ff
speednumber1
<lz-activity-rings size="44" accent="#fa114f" color="#30d158" color-weak="#32d7ff"></lz-activity-rings>
import { ActivityRings } from "loading-state-zoo/react";

<ActivityRings size={44} accent={"#fa114f"} color={"#30d158"} colorWeak={"#32d7ff"} />

Music

Waveform

lz-waveform

A mirrored audio waveform pulsing around a center line. audio apps · playing states · podcast waits

AttributeTypeDefault
sizenumber32
countnumber11
colorstring#f5f5f7
accentstring#0a84ff
speednumber1
VariableDefaultPurpose
--lz-wf-min0.22Resting bar scale
<lz-waveform size="32" count="11"></lz-waveform>
import { Waveform } from "loading-state-zoo/react";

<Waveform size={32} count={11} />

Vinyl

lz-vinyl

A spinning record with a light sheen, label, spindle and a gently bobbing tonearm. music apps · retro waits · album screens

AttributeTypeDefault
sizenumber48
accentstring#0a84ff
colorstring#f5f5f7
speednumber1
<lz-vinyl size="48"></lz-vinyl>
import { Vinyl } from "loading-state-zoo/react";

<Vinyl size={48} />

MusicNote

lz-music-note

Drawn musical notes with heads, stems and flags bobbing in a sing-song rhythm. music players · karaoke · playful waits

AttributeTypeDefault
sizenumber32
countnumber2
colorstring#f5f5f7
speednumber1
VariableDefaultPurpose
--lz-note-bob0.35emNote bob height
<lz-music-note size="32" count="2"></lz-music-note>
import { MusicNote } from "loading-state-zoo/react";

<MusicNote size={32} count={2} />

Skeletons

SkeletonShimmer

lz-skeleton-shimmer

A rounded block with a light sweeping across it. image/profile/card placeholders

AttributeTypeDefault
widthnumber120
heightnumber28
trackColor (web: track-color)string#1c1c1e
speednumber1
VariableDefaultPurpose
--lz-sheen-from-120%Sheen start
--lz-sheen-to220%Sheen end
<lz-skeleton-shimmer width="120" height="28"></lz-skeleton-shimmer>
import { SkeletonShimmer } from "loading-state-zoo/react";

<SkeletonShimmer width={120} height={28} />

SkeletonCard

lz-skeleton-card

A composite card skeleton with an avatar circle and text lines under one shared sheen. profile cards · feed items · user rows

AttributeTypeDefault
widthnumber200
heightnumber64
trackColor (web: track-color)string#1c1c1e
speednumber1
VariableDefaultPurpose
--lz-sheen-from-120%Sheen start
--lz-sheen-to220%Sheen end
<lz-skeleton-card width="200" height="64"></lz-skeleton-card>
import { SkeletonCard } from "loading-state-zoo/react";

<SkeletonCard width={200} height={64} />

SkeletonList

lz-skeleton-list

Repeated list rows with avatars and text lines under one shared sheen. chat lists · inbox rows · search results

AttributeTypeDefault
widthnumber180
rowsnumber4
trackColor (web: track-color)string#1c1c1e
speednumber1
VariableDefaultPurpose
--lz-sheen-from-120%Sheen start
--lz-sheen-to220%Sheen end
<lz-skeleton-list width="180" rows="4"></lz-skeleton-list>
import { SkeletonList } from "loading-state-zoo/react";

<SkeletonList width={180} rows={4} />

Deterministic progress

ProgressRing and ProgressBar are deterministic. Feed them your real upload, download, or task value via percent (clamped 0–100). Re-rendering updates the fill and aria-valuenow, so screen readers get live progress.

<ProgressRing percent={65} size={56} strokeWidth={6} color="#0a84ff" />
<ProgressBar  percent={65} width={220} height={8} color="#0a84ff" />

Motion guidelines

  • Animate transforms and opacity only — never layout properties.
  • Spinners for actions under 5s; skeletons for content fetches.
  • Determinate progress only when you actually know the value.
  • Keep cycle times between 0.8s and 1.4s.
Loading State ZooFree · personal & commercial use