# Skeleton

A placeholder block that takes the place of content while the content loads.

```tsx
import { Skeleton } from 'ferry-ui'

export default function SkeletonHero() {
  return (
    <div aria-busy="true" className="flex w-full max-w-xs items-center gap-3 rounded-lg border bg-surface-100 p-4">
      <Skeleton className="size-10 rounded-full" />
      <div className="flex flex-1 flex-col gap-2">
        <Skeleton className="h-4 w-32" />
        <Skeleton className="h-3.5 w-44" />
      </div>
    </div>
  )
}
```

## Usage guidelines

- **For the first load.** Use a skeleton while a page, a list or a value loads for the first time.
- **Same size as the content.** A skeleton has no size of its own. Give it the size of the content that it replaces.
- **Use the built-in states first.** [Metric Card](/docs/components/metric-card), [Info Tile](/docs/components/info-tile) and the items of a [Description List](/docs/components/description-list) have a `loading` prop. [Table States](/docs/components/table-states) and [Resource Card](/docs/components/resource-card) have their own skeleton components.
- **An action in progress is not a skeleton.** For an action, use the `loading` prop of [Button](/docs/components/button).

## Anatomy

Import the component. A skeleton has one part.

```tsx title="Anatomy"

<Skeleton className="h-4 w-32" />
```

## Examples

### Shapes

Set the size and the radius with `className`. This demo shows an avatar, a square picture, a badge, a field and a line of text.

```tsx
import { Skeleton } from 'ferry-ui'

export default function SkeletonShapes() {
  return (
    <>
      {/* An avatar */}
      <Skeleton className="size-8 rounded-full" />
      {/* A square picture */}
      <Skeleton className="size-10 rounded-md" />
      {/* A badge */}
      <Skeleton className="h-5 w-12 rounded-full" />
      {/* A field or a button */}
      <Skeleton className="h-[34px] w-28" />
      {/* A line of text */}
      <Skeleton className="h-4 w-40" />
    </>
  )
}
```

### Text

Use one skeleton for each line of text. Make the last line shorter.

```tsx
import { Skeleton } from 'ferry-ui'

export default function SkeletonText() {
  return (
    <div aria-busy="true" className="flex w-full max-w-xs flex-col gap-2">
      <Skeleton className="h-5 w-40" />
      <Skeleton className="h-3.5 w-full" />
      <Skeleton className="h-3.5 w-full" />
      <Skeleton className="h-3.5 w-3/4" />
    </div>
  )
}
```

### List

Use one skeleton for each row of a list. Give each skeleton the height of a row.

```tsx
import { Skeleton } from 'ferry-ui'

export default function SkeletonList() {
  return (
    <div aria-busy="true" className="flex w-full max-w-sm flex-col gap-2">
      <Skeleton className="h-11 w-full" />
      <Skeleton className="h-11 w-full" />
      <Skeleton className="h-11 w-full" />
    </div>
  )
}
```

### From skeleton to content

Show the skeleton while the data loads. Then show the content in the same place. Because the sizes are the same, the layout does not move.

```tsx
import * as React from 'react'
import { Avatar, AvatarFallback, Button, Skeleton } from 'ferry-ui'

export default function SkeletonContent() {
  const [loading, setLoading] = React.useState(false)

  function reload() {
    setLoading(true)
    window.setTimeout(() => setLoading(false), 1500)
  }

  return (
    <div className="flex w-full max-w-xs flex-col gap-4">
      <div aria-busy={loading} className="flex items-center gap-3 rounded-lg border bg-surface-100 p-4">
        {loading ? (
          <>
            <Skeleton className="size-8 rounded-full" />
            <div className="flex h-10 flex-col justify-center gap-1.5">
              <Skeleton className="h-4 w-24" />
              <Skeleton className="h-3.5 w-36" />
            </div>
          </>
        ) : (
          <>
            <Avatar>
              <AvatarFallback>MC</AvatarFallback>
            </Avatar>
            <div className="flex h-10 flex-col justify-center">
              <span className="text-sm font-medium text-foreground">Maya Chen</span>
              <span className="text-[13px] text-foreground-light">maya@example.com</span>
            </div>
          </>
        )}
      </div>
      <Button className="self-start" loading={loading} onClick={reload}>
        Load again
      </Button>
    </div>
  )
}
```

## Accessibility

- Assistive technology does not see a skeleton. Set `aria-busy` on the region that loads.
- The skeleton pulses. The pulse stops when the user prefers reduced motion.

## API reference

`Skeleton` accepts each attribute of the `<div>` element.

`Skeleton` has no props of its own. It accepts the attributes of the element it renders.
