Ghostly
Guides

Examples

Real-world patterns and common use cases for Ghostly.

Single component

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

function UserPage() {
  const { data, isLoading } = useQuery('user')

  return (
    <Ghostly loading={isLoading} smooth>
      <UserProfile user={data} />
    </Ghostly>
  )
}

Product grid

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

function ShopPage() {
  const { data: products, isLoading } = useQuery('products')

  return (
    <GhostlyList
      loading={isLoading}
      count={8}
      item={<ProductCard />}
      className="grid grid-cols-2 gap-4 md:grid-cols-4"
    >
      {products?.map(p => <ProductCard key={p.id} product={p} />)}
    </GhostlyList>
  )
}

Suspense-powered (zero state management)

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

function ProductPage({ id }: { id: string }) {
  return (
    <GhostlySuspense fallback={<ProductCard />} animation="shimmer" smooth>
      <AsyncProductCard id={id} />
    </GhostlySuspense>
  )
}

Dashboard with multiple sections

function DashboardPage() {
  const stats = useQuery('stats')
  const orders = useQuery('orders')
  const chart = useQuery('chart')

  return (
    <div className="space-y-8">
      <Ghostly loading={stats.isLoading} animation="pulse" smooth>
        <StatsRow stats={stats.data} />
      </Ghostly>

      <Ghostly loading={chart.isLoading} animation="shimmer" smooth>
        <RevenueChart data={chart.data} />
      </Ghostly>

      <GhostlyList
        loading={orders.isLoading}
        count={5}
        item={<OrderRow />}
        animation="wave"
        as="ul"
        className="flex flex-col divide-y"
      >
        {orders.data?.map(o => <OrderRow key={o.id} order={o} />)}
      </GhostlyList>
    </div>
  )
}

Exclude elements

<Ghostly loading={isLoading}>
  <div className="flex items-center justify-between p-4 border rounded-lg">
    <div>
      <h3>{data?.title ?? ''}</h3>
      <p>{data?.description ?? ''}</p>
    </div>
    <button data-ghostly-ignore className="btn-primary">
      Share
    </button>
  </div>
</Ghostly>

Custom colors per section

<Ghostly
  loading={true}
  color="hsl(260 30% 88%)"
  shine="hsl(260 30% 94%)"
>
  <SpecialSection />
</Ghostly>

Control skeleton line count

<Ghostly loading={isLoading}>
  <div>
    <h2>{data?.title ?? ''}</h2>
    <p data-ghostly-lines="1">{data?.subtitle ?? ''}</p>
    <p data-ghostly-lines="5">{data?.body ?? ''}</p>
  </div>
</Ghostly>

Custom image aspect ratios

<Ghostly loading={isLoading}>
  <div className="flex gap-4">
    <img data-ghostly-ratio="1/1" src={data?.avatar} alt="" className="w-16 h-16 rounded-full" />
    <div>
      <h3>{data?.name ?? ''}</h3>
      <p>{data?.bio ?? ''}</p>
    </div>
  </div>
</Ghostly>

useGhostly for custom skeleton elements

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

function CustomWidget() {
  const { loading, getGhostlyProps } = useGhostly()

  return (
    <div {...getGhostlyProps()}>
      <canvas className="w-full h-48" />
      <p>Chart description</p>
    </div>
  )
}

// Wrap in Ghostly to activate
<Ghostly loading={isLoading}>
  <CustomWidget />
</Ghostly>