Ghostly
Guides

Suspense Integration

Using Ghostly with React Suspense, RSC, and streaming SSR.

The easiest way to use Ghostly with Suspense. No loading state to manage.

import { GhostlySuspense } from '@ghostly-ui/react'

<GhostlySuspense fallback={<ProductCard />}>
  <AsyncProductCard />
</GhostlySuspense>

GhostlySuspense wraps React's <Suspense> and automatically renders your fallback inside <Ghostly loading={true}> as the Suspense boundary fallback.

This is the recommended approach for any project using React Server Components, the use() hook, or data-fetching libraries with Suspense support.

With options

<GhostlySuspense
  fallback={<UserProfile />}
  animation="pulse"
  radius="lg"
  color="hsl(260 30% 88%)"
  smooth
>
  <AsyncUserProfile userId={123} />
</GhostlySuspense>

Multiple boundaries

<div className="grid grid-cols-12 gap-6">
  <div className="col-span-8">
    <GhostlySuspense fallback={<Chart />} animation="shimmer">
      <AsyncChart />
    </GhostlySuspense>
  </div>
  <div className="col-span-4">
    <GhostlySuspense fallback={<Feed />} animation="wave">
      <AsyncFeed />
    </GhostlySuspense>
  </div>
</div>

Manual Suspense fallback

If you need more control, use <Ghostly> directly as a Suspense fallback:

import { Suspense } from 'react'
import { Ghostly } from '@ghostly-ui/react'

<Suspense fallback={
  <Ghostly loading={true}>
    <ProductCard />
  </Ghostly>
}>
  <AsyncProductCard />
</Suspense>

Next.js loading.tsx

app/products/loading.tsx
import { GhostlyList } from '@ghostly-ui/react'
import { ProductCard } from '@/components/product-card'

export default function Loading() {
  return (
    <GhostlyList loading={true} count={6} item={<ProductCard />} className="grid grid-cols-3 gap-4">
      <></>
    </GhostlyList>
  )
}

Why it works with streaming SSR

Ghostly's CSS-first approach is perfect for streaming:

  1. CSS loads once in <head>
  2. Streamed boundaries arrive with data-ghostly attribute
  3. When data resolves, the attribute is removed
  4. No hydration mismatch — attribute is set server-side