Loading Skeletons
Architecture pattern for loading states and skeleton components
Overview
Danvas uses granular Suspense boundaries with component-coupled skeleton primitives for optimal perceived performance. This document outlines the standard pattern.
Architectural Principles
1. Granular Suspense Boundaries
Route-level loading.tsx blocks the entire page layout from rendering until all data-fetching finishes. We prefer to render the page shell (menus, headers, actions) instantly and wrap individual data-fetching Server Components in React <Suspense> boundaries.
2. Component-Coupled Skeletons
When a component fetches data or requires a skeleton, its skeleton should be implemented in a colocated file (e.g., user-card-skeleton.tsx next to user-card.tsx).
Skeletons should not be exported as sub-properties on the main component (e.g. <UserCard.Skeleton />) because this forces Next.js to bundle the parent component's weight even when only the skeleton is imported.
3. Design-System Skeleton Primitives
Avoid manual composition of raw Skeleton divs with magic height/width Tailwind utilities. Use reusable primitives from @repo/design-system/components/ui/skeleton:
| Primitive | Usage |
|---|---|
<SkeletonText lines={n} /> | Text blocks; automatic shorter last line if lines > 1 |
<SkeletonAvatar size="sm" | "md" | "lg" /> | Avatar placeholders |
<SkeletonButton /> | Button placeholders |
Implementation Recipe
Step 1: Define the Skeleton Component
Create components/my-feature-skeleton.tsx. Mimic the exact DOM nodes of the real component but swap text and image nodes for skeleton primitives.