Motion reveal

Cards animate in when they scroll into view. Each card staggers slightly using MotionReveal.

Pick an animation style below. Cards load with skeletons on first visit. Toggle Simulate loading to show or hide the skeleton UI — On keeps skeletons visible, Off shows the cards again.

Reveal animation

Use MotionReveal with a staggered delay so each card enters in sequence as it becomes visible.

import { MotionReveal } from '@/animations';
import { Card } from '@/ui/components/card';
 
const MOTION_REVEAL_STAGGER_MS = 100;
 
function CardGrid() {
  return (
    <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
      {cards.map((image, index) => (
        <MotionReveal
          key={`${index}-${animation}`}
          animation={animation}
          delay={index * MOTION_REVEAL_STAGGER_MS}
        >
          <Card
            title={`Card ${index + 1}`}
            description="Card description"
            media={image}
          />
        </MotionReveal>
      ))}
    </div>
  );
}
Pick an animation:
Simulate loading:
Loading cards

Loading UI

Wrap the grid in Suspense and use CardSkeleton as the fallback while data loads. The demo uses the same markup for Simulate loading and the Suspense fallback.

import { Suspense } from 'react';
import { CardSkeleton } from '@/ui/components/card-skeleton';
import { placeholderImageList } from '@/assets';
 
<Suspense
  fallback={
    <div
      className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3"
      role="status"
      aria-busy="true"
      aria-live="polite"
    >
      <span className="sr-only">Loading cards</span>
      {placeholderImageList.map((_, index) => (
        <CardSkeleton key={index} />
      ))}
    </div>
  }
>
  <CardGrid />
</Suspense>

Next.js docs: Loading UI and Streaming