# Skeleton

A pulsing placeholder in the shape of content that is still loading.

```tsx
import { Skeleton } from "@zenoxai/ui/components/skeleton"

function SkeletonDemo() {
  return (
    <div className="flex w-full max-w-xs items-center gap-3">
      <Skeleton className="size-9 rounded-full" />
      <div className="flex flex-1 flex-col gap-2">
        <Skeleton className="h-3.5 w-3/4" />
        <Skeleton className="h-3 w-1/2" />
      </div>
    </div>
  )
}
```

## Usage

```tsx
import { Skeleton } from "@zenoxai/ui/components/skeleton"

export function AlertTitleSkeleton() {
  return (
    <div className="flex flex-col gap-2">
      <Skeleton className="h-3.5 w-3/4" />
      <Skeleton className="h-3 w-1/2" />
    </div>
  )
}
```

Use skeletons on the first load of a view whose layout is known: a table, a card, a detail
panel. They hold the space the content will take, so nothing jumps when the data arrives.

`Skeleton` is an empty `div` with a muted background and a pulse. It has no size of its own:
set `h-*` and `w-*` to match the element it stands in for, and `rounded-full` for avatars and
icons. Match the height of text lines to the type scale: `h-3.5` for 12.5px body text, `h-4`
or `h-5` for titles.

Use something else when:

- The wait is short and has no fixed layout, such as a button action: use a
  [Spinner](/components/spinner).
- The operation reports its progress: use a [Progress](/components/progress) bar.
- The data is already on screen and is refreshing: keep it visible and show a spinner
  instead of blanking it.

## Examples

### Card

Mirror the structure of the real card: title, description, the main value, then the body.
Keep the real `Card` around the skeletons so the border and padding do not change on load.

```tsx
import { Card, CardContent, CardHeader } from "@zenoxai/ui/components/card"
import { Skeleton } from "@zenoxai/ui/components/skeleton"

function SkeletonCard() {
  return (
    <Card className="w-full max-w-xs" aria-busy="true">
      <span className="sr-only">Loading exposure summary</span>
      <CardHeader>
        <Skeleton className="h-4 w-32" />
        <Skeleton className="h-3 w-48" />
      </CardHeader>
      <CardContent className="flex flex-col gap-3">
        <Skeleton className="h-8 w-20" />
        <Skeleton className="h-24 w-full" />
        <div className="flex gap-2">
          <Skeleton className="h-5 w-16" />
          <Skeleton className="h-5 w-16" />
        </div>
      </CardContent>
    </Card>
  )
}
```

### Table rows

Keep the real header and render skeleton cells in a few rows, sized like the column content.
Five rows are enough to read as a table; do not fill the viewport.

```tsx
import { Skeleton } from "@zenoxai/ui/components/skeleton"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@zenoxai/ui/components/table"

function SkeletonTable() {
  return (
    <div className="w-full max-w-xl" aria-busy="true">
      <span className="sr-only">Loading alerts</span>
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>Alert</TableHead>
            <TableHead>Severity</TableHead>
            <TableHead>Asset</TableHead>
            <TableHead className="text-right">First seen</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {[0, 1, 2, 3, 4].map((row) => (
            <TableRow key={row}>
              <TableCell>
                <Skeleton className="h-3.5 w-40" />
              </TableCell>
              <TableCell>
                <Skeleton className="h-5 w-16" />
              </TableCell>
              <TableCell>
                <Skeleton className="h-3.5 w-28" />
              </TableCell>
              <TableCell>
                <Skeleton className="ml-auto h-3.5 w-20" />
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </div>
  )
}
```

### Text

For a paragraph, vary the widths and make the last line shorter, like real text.

```tsx
import { Skeleton } from "@zenoxai/ui/components/skeleton"

function SkeletonText() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-2">
      <Skeleton className="h-5 w-2/3" />
      <Skeleton className="h-3.5 w-full" />
      <Skeleton className="h-3.5 w-full" />
      <Skeleton className="h-3.5 w-4/5" />
    </div>
  )
}
```

## Accessibility

- Skeletons are empty, so screen readers skip them. Mark the region that is loading with
  `aria-busy="true"` and add a visually hidden label ("Loading alerts") so the user knows
  something is coming. Remove both when the content renders.
- The pulse stops for users who ask for reduced motion.

## API reference

`import { ... } from "@zenoxai/ui/components/skeleton"`

### Skeleton

No props of its own.

