Skip to main content

Basic Loading Scenarios

Lumidot makes it easy to add beautiful loading animations to your React applications. Here are the most common scenarios.

Page Loading

Show a centered loading animation while your page content loads.
import { Lumidot } from 'lumidot';
import { Suspense } from 'react';

function PageLoader() {
  return (
    <div style={{
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      minHeight: '100vh'
    }}>
      <Lumidot 
        variant="blue"
        pattern="all"
        rows={3}
        cols={3}
        scale={2}
        glow={8}
      />
    </div>
  );
}

export default function App() {
  return (
    <Suspense fallback={<PageLoader />}>
      {/* Your page content */}
    </Suspense>
  );
}

Data Fetching

Display a loading animation while fetching data from an API.
import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';

function UserList() {
  const [users, setUsers] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/users')
      .then(res => res.json())
      .then(data => {
        setUsers(data);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return (
      <div style={{ padding: '2rem', textAlign: 'center' }}>
        <Lumidot 
          variant="emerald"
          pattern="wave-lr"
          rows={3}
          cols={5}
          scale={1.5}
        />
        <p style={{ marginTop: '1rem', color: '#666' }}>Loading users...</p>
      </div>
    );
  }

  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

Form Submission

Show feedback during form submission with a compact loader.
import { Lumidot } from 'lumidot';
import { useState } from 'react';

function ContactForm() {
  const [submitting, setSubmitting] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setSubmitting(true);
    
    await fetch('/api/contact', {
      method: 'POST',
      body: new FormData(e.target)
    });
    
    setSubmitting(false);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="name" placeholder="Name" />
      <input type="email" name="email" placeholder="Email" />
      <textarea name="message" placeholder="Message" />
      
      <button type="submit" disabled={submitting}>
        {submitting ? (
          <span style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
            <Lumidot 
              variant="white"
              pattern="line-h-mid"
              rows={1}
              cols={5}
              scale={0.8}
              glow={4}
            />
            Sending...
          </span>
        ) : (
          'Send Message'
        )}
      </button>
    </form>
  );
}

Button Loading State

Inline loading animation for buttons.
import { Lumidot } from 'lumidot';
import { useState } from 'react';

function SaveButton({ onSave }) {
  const [saving, setSaving] = useState(false);

  const handleClick = async () => {
    setSaving(true);
    await onSave();
    setSaving(false);
  };

  return (
    <button 
      onClick={handleClick} 
      disabled={saving}
      style={{
        display: 'flex',
        alignItems: 'center',
        gap: '0.5rem',
        padding: '0.5rem 1rem'
      }}
    >
      {saving && (
        <Lumidot 
          variant="white"
          pattern="duo-h"
          rows={1}
          cols={3}
          scale={0.7}
          glow={6}
        />
      )}
      {saving ? 'Saving...' : 'Save Changes'}
    </button>
  );
}

Card Loading Placeholder

Show a skeleton loader for card components.
import { Lumidot } from 'lumidot';

function CardSkeleton() {
  return (
    <div style={{
      border: '1px solid #e5e7eb',
      borderRadius: '8px',
      padding: '1.5rem',
      backgroundColor: '#f9fafb'
    }}>
      <div style={{ display: 'flex', justifyContent: 'center', padding: '2rem 0' }}>
        <Lumidot 
          variant="slate"
          pattern="spiral"
          rows={4}
          cols={4}
          scale={1.2}
          glow={6}
          duration={1}
        />
      </div>
    </div>
  );
}

function ProductCard({ id }) {
  const [product, setProduct] = useState(null);

  useEffect(() => {
    fetch(`/api/products/${id}`)
      .then(res => res.json())
      .then(setProduct);
  }, [id]);

  if (!product) return <CardSkeleton />;

  return (
    <div style={{
      border: '1px solid #e5e7eb',
      borderRadius: '8px',
      padding: '1.5rem'
    }}>
      <h3>{product.name}</h3>
      <p>{product.description}</p>
      <p>${product.price}</p>
    </div>
  );
}

Infinite Scroll Loading

Show a loader at the bottom of a list for infinite scroll.
import { Lumidot } from 'lumidot';
import { useEffect, useRef } from 'react';

function InfiniteList() {
  const [items, setItems] = useState([]);
  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(1);
  const observerRef = useRef(null);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting && !loading) {
          setLoading(true);
          fetch(`/api/items?page=${page}`)
            .then(res => res.json())
            .then(data => {
              setItems(prev => [...prev, ...data]);
              setPage(prev => prev + 1);
              setLoading(false);
            });
        }
      },
      { threshold: 0.1 }
    );

    if (observerRef.current) {
      observer.observe(observerRef.current);
    }

    return () => observer.disconnect();
  }, [page, loading]);

  return (
    <div>
      {items.map((item, i) => (
        <div key={i}>{item.name}</div>
      ))}
      
      <div ref={observerRef} style={{ padding: '2rem', textAlign: 'center' }}>
        {loading && (
          <Lumidot 
            variant="indigo"
            pattern="wave-tb"
            rows={5}
            cols={3}
            scale={1}
          />
        )}
      </div>
    </div>
  );
}

Tips

  • Use pattern="all" or pattern="wave-lr" for general loading states
  • Use pattern="line-h-mid" or pattern="duo-h" for inline button loaders
  • Use pattern="spiral" or pattern="frame" for card placeholders
  • Adjust scale to match your component size
  • Match variant to your design system colors

Build docs developers (and LLMs) love