Skip to main content

Responsive Design

Make your Lumidot animations responsive by adjusting rows, cols, and scale based on screen size.

Using CSS Media Queries

Adjust the loader appearance with CSS classes and media queries.
import { Lumidot } from 'lumidot';
import './responsive.css';

function ResponsiveLoader() {
  return (
    <div className="responsive-container">
      <Lumidot 
        variant="blue"
        pattern="all"
        rows={3}
        cols={3}
        className="responsive-loader"
      />
    </div>
  );
}
/* responsive.css */
.responsive-loader {
  transform: scale(1);
}

/* Mobile */
@media (max-width: 640px) {
  .responsive-loader {
    transform: scale(0.8);
  }
}

/* Tablet */
@media (min-width: 641px) and (max-width: 1024px) {
  .responsive-loader {
    transform: scale(1.2);
  }
}

/* Desktop */
@media (min-width: 1025px) {
  .responsive-loader {
    transform: scale(1.5);
  }
}

Using Window Size Hook

Dynamically adjust props based on viewport width.
import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';

function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: typeof window !== 'undefined' ? window.innerWidth : 0,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({ width: window.innerWidth });
    }

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowSize;
}

function AdaptiveLoader() {
  const { width } = useWindowSize();

  // Adjust based on screen size
  const getLoaderProps = () => {
    if (width < 640) {
      // Mobile: smaller, simpler
      return { rows: 2, cols: 2, scale: 1, glow: 6 };
    } else if (width < 1024) {
      // Tablet: medium
      return { rows: 3, cols: 3, scale: 1.2, glow: 8 };
    } else {
      // Desktop: larger, more complex
      return { rows: 4, cols: 4, scale: 1.5, glow: 10 };
    }
  };

  const props = getLoaderProps();

  return (
    <div style={{ display: 'flex', justifyContent: 'center', padding: '2rem' }}>
      <Lumidot 
        variant="emerald"
        pattern="spiral"
        {...props}
      />
    </div>
  );
}

Container Query Approach

Respond to container size instead of viewport.
import { Lumidot } from 'lumidot';
import { useRef, useState, useEffect } from 'react';

function ContainerAdaptiveLoader() {
  const containerRef = useRef(null);
  const [containerWidth, setContainerWidth] = useState(0);

  useEffect(() => {
    const observer = new ResizeObserver(entries => {
      for (let entry of entries) {
        setContainerWidth(entry.contentRect.width);
      }
    });

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

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

  const getScale = () => {
    if (containerWidth < 200) return 0.6;
    if (containerWidth < 400) return 1;
    if (containerWidth < 600) return 1.5;
    return 2;
  };

  return (
    <div ref={containerRef} style={{ width: '100%', textAlign: 'center' }}>
      <Lumidot 
        variant="purple"
        pattern="wave-lr"
        rows={3}
        cols={4}
        scale={getScale()}
      />
    </div>
  );
}

Mobile-First Pattern Selection

Use simpler patterns on mobile, complex patterns on desktop.
import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';

function PatternAdaptiveLoader() {
  const [isMobile, setIsMobile] = useState(false);

  useEffect(() => {
    const checkMobile = () => setIsMobile(window.innerWidth < 768);
    checkMobile();
    window.addEventListener('resize', checkMobile);
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  return (
    <Lumidot 
      variant="cyan"
      pattern={isMobile ? 'line-h-mid' : 'spiral'}
      rows={isMobile ? 1 : 4}
      cols={isMobile ? 5 : 4}
      scale={isMobile ? 1 : 1.5}
      glow={isMobile ? 6 : 10}
    />
  );
}

Breakpoint-Based Component

Create a wrapper component with predefined breakpoints.
import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';

type Breakpoint = 'mobile' | 'tablet' | 'desktop';

interface ResponsiveLumidotProps {
  variant?: string;
  pattern?: string;
  mobile?: { rows: number; cols: number; scale: number; glow: number };
  tablet?: { rows: number; cols: number; scale: number; glow: number };
  desktop?: { rows: number; cols: number; scale: number; glow: number };
}

function ResponsiveLumidot({ 
  variant = 'blue', 
  pattern = 'all',
  mobile = { rows: 2, cols: 2, scale: 0.8, glow: 6 },
  tablet = { rows: 3, cols: 3, scale: 1.2, glow: 8 },
  desktop = { rows: 4, cols: 4, scale: 1.5, glow: 10 }
}: ResponsiveLumidotProps) {
  const [breakpoint, setBreakpoint] = useState<Breakpoint>('desktop');

  useEffect(() => {
    const updateBreakpoint = () => {
      const width = window.innerWidth;
      if (width < 768) setBreakpoint('mobile');
      else if (width < 1024) setBreakpoint('tablet');
      else setBreakpoint('desktop');
    };

    updateBreakpoint();
    window.addEventListener('resize', updateBreakpoint);
    return () => window.removeEventListener('resize', updateBreakpoint);
  }, []);

  const props = breakpoint === 'mobile' ? mobile : 
                breakpoint === 'tablet' ? tablet : desktop;

  return (
    <Lumidot 
      variant={variant}
      pattern={pattern}
      {...props}
    />
  );
}

// Usage
function App() {
  return (
    <ResponsiveLumidot 
      variant="indigo"
      pattern="spiral"
      mobile={{ rows: 2, cols: 2, scale: 0.7, glow: 4 }}
      tablet={{ rows: 3, cols: 3, scale: 1, glow: 6 }}
      desktop={{ rows: 5, cols: 5, scale: 2, glow: 12 }}
    />
  );
}

Responsive Card Grid

Adapt loader size within a responsive grid layout.
import { Lumidot } from 'lumidot';

function ResponsiveGrid() {
  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
      gap: '1.5rem',
      padding: '2rem'
    }}>
      {[1, 2, 3, 4, 5, 6].map(i => (
        <div 
          key={i}
          style={{
            border: '1px solid #e5e7eb',
            borderRadius: '8px',
            padding: '2rem',
            textAlign: 'center',
            minHeight: '200px',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center'
          }}
        >
          <Lumidot 
            variant="teal"
            pattern="frame-sync"
            rows={3}
            cols={3}
            scale={1}
            glow={8}
            style={{ width: '100%', maxWidth: '80px' }}
          />
        </div>
      ))}
    </div>
  );
}

Flexible Container

Make the loader fill its container responsively.
import { Lumidot } from 'lumidot';

function FlexibleLoader() {
  return (
    <div style={{
      width: '100%',
      maxWidth: '600px',
      margin: '0 auto',
      padding: '2rem',
      display: 'flex',
      justifyContent: 'center',
      alignItems: 'center',
      minHeight: '300px',
      background: '#f9fafb',
      borderRadius: '12px'
    }}>
      <Lumidot 
        variant="violet"
        pattern="all"
        rows={4}
        cols={4}
        scale={1.5}
        glow={10}
        style={{
          maxWidth: '100%',
          height: 'auto'
        }}
      />
    </div>
  );
}

Orientation-Aware Layout

Adjust rows and cols based on device orientation.
import { Lumidot } from 'lumidot';
import { useState, useEffect } from 'react';

function OrientationAwareLoader() {
  const [isPortrait, setIsPortrait] = useState(true);

  useEffect(() => {
    const checkOrientation = () => {
      setIsPortrait(window.innerHeight > window.innerWidth);
    };

    checkOrientation();
    window.addEventListener('resize', checkOrientation);
    window.addEventListener('orientationchange', checkOrientation);
    
    return () => {
      window.removeEventListener('resize', checkOrientation);
      window.removeEventListener('orientationchange', checkOrientation);
    };
  }, []);

  return (
    <Lumidot 
      variant="orange"
      pattern="wave-lr"
      rows={isPortrait ? 5 : 3}
      cols={isPortrait ? 3 : 5}
      scale={1.2}
      glow={8}
    />
  );
}

Tips

  • Start with scale adjustments before changing rows and cols
  • Reduce glow on mobile to improve performance
  • Use simpler patterns (fewer animated dots) on smaller screens
  • Consider container size, not just viewport size
  • Test on real devices to ensure smooth animations
  • Use prefers-reduced-motion for accessibility (Lumidot handles this automatically)

Build docs developers (and LLMs) love