Skip to main content
Lumidot is designed with accessibility in mind, automatically respecting user preferences and following best practices for loading indicators.

Prefers Reduced Motion

Lumidot automatically respects the prefers-reduced-motion media query, which indicates that users prefer reduced or minimal animation.

How It Works

For patterns using wave mode (most patterns), animations continue normally even when prefers-reduced-motion is enabled, as the wave animation is subtle and doesn’t involve rapid or jarring motion.
// Wave mode patterns are not affected
<Lumidot pattern="all" />       // Continues animating
<Lumidot pattern="frame" />     // Continues animating
<Lumidot pattern="wave-lr" />   // Continues animating

Testing Reduced Motion

You can test the reduced motion behavior in several ways:
# Enable reduced motion:
# System Preferences → Accessibility → Display → Reduce motion

Semantic HTML

Lumidot uses semantic HTML attributes to ensure screen readers and assistive technologies can properly interpret the loading state.

ARIA Attributes

<Lumidot pattern="all" variant="blue" />
Renders as:
<span role="status" aria-label="Loading" data-lumidot="" ...>
  <!-- dot elements -->
</span>
  • role="status" — Indicates this is a status update region
  • aria-label="Loading" — Provides a text alternative for screen readers
The role="status" is a live region that announces changes politely, without interrupting the user.

Screen Reader Announcements

When a Lumidot loader appears, screen readers will announce “Loading” to inform users that content is being loaded.

Best Practices

For inline loading indicators, the default label is sufficient:
<button disabled>
  <Lumidot scale={0.6} pattern="line-h-mid" variant="white" />
  <span>Processing...</span>
</button>
Screen readers will announce: “Loading, Processing…, button, disabled”

Color Contrast

Ensure sufficient color contrast between the loader and its background for users with visual impairments.

WCAG Guidelines

Animated content does not have strict WCAG contrast requirements, but for loading indicators that may be visible for extended periods, aim for at least 3:1 contrast ratio.

Contrast Examples

<div style={{ background: '#1f2937', padding: '40px' }}>
  <Lumidot variant="cyan" glow={12} />     {/* High contrast */}
  <Lumidot variant="emerald" glow={12} /> {/* High contrast */}
  <Lumidot variant="white" glow={10} />   {/* High contrast */}
</div>

Checking Contrast

Use browser DevTools or online tools:

Keyboard Navigation

Lumidot loaders are not interactive elements and do not receive keyboard focus, which is appropriate for loading indicators.

Focus Management

When a button is loading, disable it and trap focus:
function SubmitButton({ isLoading }: { isLoading: boolean }) {
  return (
    <button disabled={isLoading} type="submit">
      {isLoading ? (
        <>
          <Lumidot scale={0.5} pattern="line-h-mid" variant="white" />
          <span>Submitting...</span>
        </>
      ) : (
        'Submit'
      )}
    </button>
  );
}
The disabled attribute prevents keyboard interaction while loading.

Timing Considerations

Minimum Display Time

For very fast operations, consider showing the loader for a minimum duration to avoid jarring flashes:
function useMinimumLoading(isLoading: boolean, minDuration = 500) {
  const [showLoader, setShowLoader] = React.useState(false);
  const startTimeRef = React.useRef<number | null>(null);

  React.useEffect(() => {
    if (isLoading) {
      startTimeRef.current = Date.now();
      setShowLoader(true);
    } else if (startTimeRef.current) {
      const elapsed = Date.now() - startTimeRef.current;
      const remaining = Math.max(0, minDuration - elapsed);
      
      setTimeout(() => {
        setShowLoader(false);
        startTimeRef.current = null;
      }, remaining);
    }
  }, [isLoading, minDuration]);

  return showLoader;
}

function MyComponent() {
  const [isLoading, setIsLoading] = React.useState(false);
  const showLoader = useMinimumLoading(isLoading, 500);
  
  return showLoader ? <Lumidot pattern="all" /> : <div>Content</div>;
}

Maximum Wait Time

For long operations, provide feedback or alternatives:
function LongLoadingIndicator() {
  const [seconds, setSeconds] = React.useState(0);
  
  React.useEffect(() => {
    const interval = setInterval(() => {
      setSeconds(s => s + 1);
    }, 1000);
    
    return () => clearInterval(interval);
  }, []);
  
  return (
    <div role="status" aria-live="polite">
      <Lumidot pattern="frame" variant="blue" scale={1.5} />
      <p className="sr-only">Still loading... {seconds} seconds elapsed</p>
      {seconds > 10 && (
        <p style={{ marginTop: '1rem' }}>
          This is taking longer than expected. <button>Cancel</button>
        </p>
      )}
    </div>
  );
}

Accessibility Checklist

Use this checklist to ensure your Lumidot implementation is accessible:
  • Sufficient color contrast (3:1 minimum)
  • Loader is visible against background
  • Glow effect is not overwhelming
  • Animation is not too fast or jarring (consider duration prop)
  • Loader does not flash for very short operations
  • prefers-reduced-motion is respected (automatic)
  • Sequence mode patterns show all dots when motion is reduced (automatic)
  • Animation duration is reasonable (0.4-1.2s recommended)
  • No rapid flashing or strobing effects
  • role="status" is present (automatic)
  • aria-label="Loading" is present (automatic)
  • Additional context provided for complex loaders
  • Progress updates announced for long operations
  • Loading state is announced when it appears
  • Interactive elements are disabled during loading
  • Focus is managed appropriately
  • Focus returns to appropriate element after loading
  • No keyboard traps
  • Minimum display time for fast operations (300-500ms)
  • Maximum wait time before offering alternatives (10-15s)
  • Progress indication for operations >3 seconds
  • Cancel/retry options for long operations

Additional Resources

WCAG Guidelines

Web Content Accessibility Guidelines

MDN Accessibility

Accessibility documentation and guides

A11y Project

Community-driven accessibility resources

WebAIM

Web accessibility training and tools

Next Steps

Patterns

Explore all 36 animation patterns

Colors

Learn about color variants