---
title: Skeleton
related:
  - title: Circular Progress
    path: circular-progress.md
  - title: Inner Loading
    path: inner-loading.md
  - title: Spinners
    path: spinners.md
  - title: Loading Plugin
    path: ../quasar-plugins/loading.md
  - title: Loading Bar Plugin
    path: ../quasar-plugins/loading-bar.md
---
The QSkeleton is a component for displaying a placeholder preview of your content before you load the actual page data. It's a nice way of informing the user of what to expect from the page before it is fully loaded and increases the perceived performance. It can be used to incrementally display information on screen as data is being fetched.

## QSkeleton API

### Props

- `dark` (boolean, optional), default `null`
  Notify the component that the background is a dark color
- `type` (string, optional), default `'rect'`
  Type of skeleton placeholder
  Accepts: `'text'`, `'rect'`, `'circle'`, `'QBtn'`, `'QBadge'`, `'QChip'`, `'QToolbar'`, `'QCheckbox'`, `'QRadio'`, `'QToggle'`, `'QSlider'`, `'QRange'`, `'QInput'`, `'QAvatar'`
- `animation` (string, optional), default `'wave'`
  The animation effect of the skeleton placeholder
  Accepts: `'wave'`, `'pulse'`, `'pulse-x'`, `'pulse-y'`, `'fade'`, `'blink'`, `'none'`
- `animation-speed` (string | number, optional), default `1500`
  Animation speed (in milliseconds, without unit)
  Examples: `500`, `'1200'`
- `square` (boolean, optional)
  Removes border-radius so borders are squared
- `bordered` (boolean, optional)
  Applies a default border to the component
- `size` (string, optional)
  Size in CSS units, including unit name; Overrides 'height' and 'width' props and applies the value to both height and width
  Examples: `'16px'`, `'2rem'`
- `width` (string, optional)
  Width in CSS units, including unit name; Apply custom width; Use this prop or through CSS; Overridden by 'size' prop if used
  Examples: `'16px'`, `'2rem'`
- `height` (string, optional)
  Height in CSS units, including unit name; Apply custom height; Use this prop or through CSS; Overridden by 'size' prop if used
  Examples: `'16px'`, `'2rem'`
- `tag` (string, optional), default `'div'`
  HTML tag to use
  Examples: `'div'`, `'span'`

### Slots

- `#default`
  Default slot in the devland unslotted content of the component

## Usage

Example "On a QCard":

```vue
<template>
  <q-card style="max-width: 300px">
    <q-item>
      <q-item-section avatar>
        <q-skeleton type="QAvatar" />
      </q-item-section>

      <q-item-section>
        <q-item-label>
          <q-skeleton type="text" />
        </q-item-label>
        <q-item-label caption>
          <q-skeleton type="text" />
        </q-item-label>
      </q-item-section>
    </q-item>

    <q-skeleton height="200px" square />

    <q-card-actions align="right" class="q-gutter-md">
      <q-skeleton type="QBtn" />
      <q-skeleton type="QBtn" />
    </q-card-actions>
  </q-card>
</template>
```

### Predefined types

Below you can see the predefined types. There are some basic types (text, rect, circle) and also some special convenience types that accurately respect Quasar components size and border radius.

Example "QSkeleton types":

```vue
<template>
  <div class="q-gutter-md row items-start">
    <q-card
      flat
      bordered
      v-for="type in skeletonTypes"
      :key="type"
      style="width: 250px"
    >
      <q-card-section>
        <div class="text-caption">"{{ type }}"</div>
      </q-card-section>

      <q-separator />

      <q-card-section>
        <q-skeleton :type="type" />
      </q-card-section>
    </q-card>
  </div>
</template>

<script setup>
const skeletonTypes = [
  'text',
  'rect',
  'circle',
  'QBtn',
  'QBadge',
  'QChip',
  'QToolbar',
  'QCheckbox',
  'QRadio',
  'QToggle',
  'QSlider',
  'QRange',
  'QInput',
  'QAvatar'
]
</script>
```

### Animations

```vue
<template>
  <div class="q-gutter-md row items-start">
    <q-card
      flat
      bordered
      v-for="animation in skeletonAnimations"
      :key="animation"
      style="width: 250px"
    >
      <q-card-section>
        <div class="text-caption">"{{ animation }}"</div>
      </q-card-section>

      <q-separator />

      <q-card-section>
        <q-skeleton :animation="animation" />
      </q-card-section>
    </q-card>
  </div>
</template>

<script setup>
const skeletonAnimations = [
  'wave',
  'pulse',
  'pulse-x',
  'pulse-y',
  'fade',
  'blink',
  'none'
]
</script>
```

### Sizing

```vue
<template>
  <div class="q-gutter-md">
    <q-skeleton type="circle" size="100px" />
    <q-skeleton width="150px" />
    <q-skeleton height="150px" />
    <q-skeleton size="50px" />
    <q-skeleton width="200px" height="100px" />
  </div>
</template>
```

### Styling

Example "Bordered":

```vue
<template>
  <div class="q-gutter-y-md">
    <q-skeleton bordered type="circle" />
    <q-skeleton bordered />
    <q-skeleton bordered square />
  </div>
</template>
```

Example "Square borders":

```vue
<template>
  <q-skeleton square />
</template>
```

Example "Custom color":

```vue
<template>
  <div class="q-gutter-md">
    <q-skeleton class="bg-accent" type="circle" />
    <q-skeleton class="bg-teal" />
    <q-skeleton class="bg-orange" animation="pulse-y" />
    <q-skeleton class="bg-indigo" />
  </div>
</template>
```

Example "Custom border":

```vue
<template>
  <div class="q-gutter-y-md">
    <q-skeleton width="100px" height="50px" class="custom-skeleton-border" />
  </div>
</template>

<style lang="sass">
.custom-skeleton-border
  border-radius: 10px 0 24px 4px
  border: 1px solid #aaa
</style>
```

### Recipes

Enjoy some pre-made recipes. Your imagination is the only limit.

Example "Youtube":

```vue
<template>
  <q-card flat style="max-width: 300px">
    <q-skeleton height="150px" square />

    <q-card-section>
      <q-skeleton type="text" class="text-subtitle1" />
      <q-skeleton type="text" width="50%" class="text-subtitle1" />
      <q-skeleton type="text" class="text-caption" />
    </q-card-section>
  </q-card>
</template>
```

Example "Facebook":

```vue
<template>
  <q-card flat bordered style="max-width: 300px">
    <q-item>
      <q-item-section avatar>
        <q-skeleton type="QAvatar" animation="fade" />
      </q-item-section>

      <q-item-section>
        <q-item-label>
          <q-skeleton type="text" animation="fade" />
        </q-item-label>
        <q-item-label caption>
          <q-skeleton type="text" animation="fade" />
        </q-item-label>
      </q-item-section>
    </q-item>

    <q-skeleton height="200px" square animation="fade" />

    <q-card-section>
      <q-skeleton type="text" class="text-subtitle2" animation="fade" />
      <q-skeleton
        type="text"
        width="50%"
        class="text-subtitle2"
        animation="fade"
      />
    </q-card-section>
  </q-card>
</template>
```

Example "Twitter":

```vue
<template>
  <q-card flat bordered style="max-width: 500px">
    <q-item>
      <q-item-section avatar>
        <q-skeleton type="QAvatar" />
      </q-item-section>

      <q-item-section>
        <q-item-label>
          <q-skeleton type="text" />
        </q-item-label>
        <q-item-label caption>
          <q-skeleton type="text" width="80%" />
        </q-item-label>
      </q-item-section>
    </q-item>

    <q-item>
      <q-item-section avatar />

      <q-item-section class="q-pl-sm">
        <q-skeleton height="150px" class="q-mb-sm" />

        <div class="row items-center justify-between no-wrap">
          <div class="row items-center">
            <q-icon
              name="chat_bubble_outline"
              color="grey-4"
              class="q-mr-sm"
              size="18px"
            />
            <q-skeleton type="text" width="30px" />
          </div>

          <div class="row items-center">
            <q-icon
              name="repeat"
              color="grey-4"
              class="q-mr-sm"
              size="18px"
            />
            <q-skeleton type="text" width="30px" />
          </div>

          <div class="row items-center">
            <q-icon
              name="favorite_border"
              color="grey-4"
              class="q-mr-sm"
              size="18px"
            />
            <q-skeleton type="text" width="30px" />
          </div>
        </div>
      </q-item-section>
    </q-item>
  </q-card>
</template>
```

Example "Twitch":

```vue
<template>
  <div style="max-width: 300px">
    <q-skeleton height="170px" square animation="fade" />

    <div class="row items-start no-wrap q-mt-sm">
      <q-skeleton size="56px" square animation="fade" />

      <div class="col q-pl-sm">
        <q-skeleton type="text" square width="30%" animation="fade" />
        <q-skeleton type="text" square height="12px" animation="fade" />
        <q-skeleton
          type="text"
          square
          height="12px"
          width="75%"
          animation="fade"
        />
      </div>
    </div>
  </div>
</template>
```

Example "Table":

```vue
<template>
  <q-markup-table>
    <thead>
      <tr>
        <th class="text-left" style="width: 150px">
          <q-skeleton animation="blink" type="text" />
        </th>
        <th class="text-right">
          <q-skeleton animation="blink" type="text" />
        </th>
        <th class="text-right">
          <q-skeleton animation="blink" type="text" />
        </th>
        <th class="text-right">
          <q-skeleton animation="blink" type="text" />
        </th>
        <th class="text-right">
          <q-skeleton animation="blink" type="text" />
        </th>
        <th class="text-right">
          <q-skeleton animation="blink" type="text" />
        </th>
      </tr>
    </thead>

    <tbody>
      <tr v-for="n in 5" :key="n">
        <td class="text-left">
          <q-skeleton animation="blink" type="text" width="85px" />
        </td>
        <td class="text-right">
          <q-skeleton animation="blink" type="text" width="50px" />
        </td>
        <td class="text-right">
          <q-skeleton animation="blink" type="text" width="35px" />
        </td>
        <td class="text-right">
          <q-skeleton animation="blink" type="text" width="65px" />
        </td>
        <td class="text-right">
          <q-skeleton animation="blink" type="text" width="25px" />
        </td>
        <td class="text-right">
          <q-skeleton animation="blink" type="text" width="85px" />
        </td>
      </tr>
    </tbody>
  </q-markup-table>
</template>
```

Example "List":

```vue
<template>
  <q-item style="max-width: 300px">
    <q-item-section avatar>
      <q-skeleton type="QAvatar" />
    </q-item-section>

    <q-item-section>
      <q-item-label>
        <q-skeleton type="text" />
      </q-item-label>
      <q-item-label caption>
        <q-skeleton type="text" width="65%" />
      </q-item-label>
    </q-item-section>
  </q-item>

  <q-item style="max-width: 300px">
    <q-item-section avatar>
      <q-skeleton type="QAvatar" />
    </q-item-section>

    <q-item-section>
      <q-item-label>
        <q-skeleton type="text" />
      </q-item-label>
      <q-item-label caption>
        <q-skeleton type="text" width="90%" />
      </q-item-label>
    </q-item-section>
  </q-item>

  <q-item style="max-width: 300px">
    <q-item-section avatar>
      <q-skeleton type="QAvatar" />
    </q-item-section>

    <q-item-section>
      <q-item-label>
        <q-skeleton type="text" width="35%" />
      </q-item-label>
      <q-item-label caption>
        <q-skeleton type="text" />
      </q-item-label>
    </q-item-section>
  </q-item>
</template>
```

## Accessibility *(v2.25+)*

QSkeleton is a decorative placeholder carrying no ARIA — a screen reader wandering into a skeleton screen finds only empty, unlabeled boxes. Hide skeletons from assistive technology with `aria-hidden="true"`, or mark the loading region itself with `aria-busy="true"` so its not-yet-ready state is conveyed instead.
