Appearance
AsyncContent
Purpose
AsyncContent provides consistent handling of async data states:
- Loading state with custom skeleton
- Error state with retry option
- Empty state with call-to-action
- Success state with render function
When to use
Use AsyncContent for:
- Any component that fetches data
- Consistent loading/error/empty patterns
- Wrapping React Query results
For full page layouts, prefer PageLayout which includes AsyncContent.
Basic usage
tsx
import { AsyncContent } from '@/shared/ui/components/AsyncContent'
import { FolderIcon, Plus } from 'lucide-react'
export function ProjectList() {
const { data: projects, isLoading, error, refetch } = useProjects()
return (
<AsyncContent
isLoading={isLoading}
error={error}
data={projects}
loadingFallback={<ProjectsSkeleton />}
errorConfig={{
title: 'Failed to load projects',
icon: FolderIcon,
onRetry: refetch,
}}
emptyConfig={{
title: 'No projects',
description: 'Create your first project',
action: { label: 'New Project', onClick: handleCreate, icon: Plus },
}}
>
{(projects) => (
<ul>
{projects.map((p) => (
<li key={p.id}>{p.name}</li>
))}
</ul>
)}
</AsyncContent>
)
}Props
| Prop | Type | Required | Description |
|---|---|---|---|
isLoading | boolean | Yes | Loading state flag |
error | Error | null | No | Error object |
data | T | Yes | The data to render |
isEmpty | boolean | ((data: T) => boolean) | No | Custom empty check |
loadingFallback | ReactNode | Yes | Loading skeleton |
errorConfig | ErrorConfig | No | Error state configuration |
emptyConfig | EmptyConfig | No | Empty state configuration |
children | (data: T) => ReactNode | Yes | Render function for success |
className | string | No | Container class |
Empty detection
By default, AsyncContent checks if data is an empty array. For non-array data, provide isEmpty:
tsx
// Object data
<AsyncContent
data={user}
isEmpty={!user}
// ...
>
{(user) => <UserProfile user={user} />}
</AsyncContent>
// Custom check
<AsyncContent
data={results}
isEmpty={(data) => data.items.length === 0}
// ...
>
{(results) => <ResultsList results={results} />}
</AsyncContent>State components
AsyncContent uses these internal components:
ErrorState— Displays error with optional retryEmptyState— Displays empty message with optional actionLoadingState— Your customloadingFallback
These are also exported from @/shared/ui/components/states for standalone use.
Notes
- The render function
childrenonly executes when data is available - Error state shows
error.messageif no custom description provided - For page-level async handling, use PageLayout