VisorVisor
FlutterWidgets

VisorLoadingDots

Three-dot animated loading indicator with staggered wave pulse and reduce-motion support.

VisorLoadingDots is a soft, brand-friendly alternative to a spinner. Three dots pulse in a staggered wave using semantic accent colors. When the system requests reduced motion, the animation halts and all dots snap to the lightest color — preserving the visual but removing the movement.

Preview

When to Use

  • Soft, brand-friendly loading state as an alternative to a spinner
  • Inline loading inside chat bubbles, text areas, or compact UI slots
  • Processing states where a gentle animation conveys progress without urgency
  • Any context where animation must respect the system reduce-motion preference

When Not to Use

  • Full-page loading states where a skeleton screen better preserves layout
  • Determinate progress (use LinearProgressIndicator with a value)
  • Contexts where a spinner (VisorLoadingIndicator) is more conventional
  • Replacing button content during loading (use VisorButton's isLoading)

Installation

npx visor add loading-dots --target flutter

Or copy components/flutter/visor_loading_dots/visor_loading_dots.dart into your project.

Basic Usage

import 'package:ui/ui.dart';

const VisorLoadingDots()

Customising Size and Colors

VisorLoadingDots(
  dotSize: 8,
  colorStart: context.visorColors.surfaceAccentSubtle,
  colorMid: context.visorColors.surfaceAccentDefault,
  colorEnd: context.visorColors.surfaceAccentStrong,
)

With Accessibility Label

VisorLoadingDots(semanticLabel: 'Loading messages')

API Reference

PropertyTypeDefaultDescription
dotSizedouble?10.0Diameter of each dot in logical pixels
colorStartColor?surfaceAccentSubtleLightest animation color
colorMidColor?surfaceAccentDefaultMiddle animation color
colorEndColor?surfaceAccentStrongDarkest animation color
semanticLabelString?nullWhen provided, wraps the widget in Semantics(label: …)

Accessibility

  • Reduce-motion aware — when MediaQuery.disableAnimations is true, all dots snap to colorStart and the animation controller pauses.
  • semanticLabel is opt-in. When omitted, the widget is purely decorative to screen readers; use liveRegion higher in the tree to announce state transitions when the indicator is the only feedback signal.

Source

  • components/flutter/visor_loading_dots/visor_loading_dots.dart
  • Quality contract audit row: docs/flutter-widget-quality-contract.md (Rec8)