← Back

Skeleton Co-location Pattern

Export skeletons alongside components, match layout structure, use with Suspense.

PublishedMarch 5, 2026111 words
Edit

Skeleton Loading

Skeletons are placeholder UI that mimics content shape, reducing perceived loading time.

Example: PostListSkeleton

From app/dashboard/_components/PostList.tsx—export skeletons alongside their components:

export async function PostList({ searchParams }) { const posts = await getPosts(filter); return posts.map(post => <PostCard post={post} />); } export function PostListSkeleton() { return ( <div className="space-y-4"> {[1, 2, 3].map(i => ( <Card key={i}> <CardHeader> <Skeleton className="h-6 w-48" /> <Skeleton className="h-4 w-24" /> </CardHeader> <CardContent> <Skeleton className="h-8 w-full" /> </CardContent> </Card> ))} </div> ); }
export async function PostList({ searchParams }) { const posts = await getPosts(filter); return posts.map(post => <PostCard post={

Using with Suspense

<Suspense fallback={<PostListSkeleton />}> <PostList searchParams={searchParams} /> </Suspense>

Keep skeletons next to their components—when you change the layout, the skeleton is right there to update.

post
}
/>
)
;
}
export
function
PostListSkeleton
(
)
{
return
(
<
div
className
=
"
space-y-4
"
>
{
[
1
,
2
,
3
]
.
map
(
i
=>
(
<
Card
key
=
{
i
}
>
<
CardHeader
>
<
Skeleton
className
=
"
h-6 w-48
"
/>
<
Skeleton
className
=
"
h-4 w-24
"
/>
</
CardHeader
>
<
CardContent
>
<
Skeleton
className
=
"
h-8 w-full
"
/>
</
CardContent
>
</
Card
>
)
)
}
</
div
>
)
;
}
<
Suspense
fallback
=
{
<
PostListSkeleton
/>
}
>
<
PostList
searchParams
=
{
searchParams
}
/>
</
Suspense
>