Skip to content

Skeleton

A loading placeholder component that displays a skeleton screen while content is loading.

NameCategoryDescriptionTypeDefault
animated? StyleWhether to show shimmer animationbooleantrue
animation? StyleAnimation style: shimmer (scanline sweep), pulse (two-frame blink), dither (checkerboard dissolve)'shimmer' | 'pulse' | 'dither''shimmer'
variant? StyleSkeleton shape variant'text' | 'circular' | 'rectangular' | 'rounded''rectangular'
width? SizeCustom width (number as px, string as-is)string | number
height? SizeCustom height (number as px, string as-is)string | number
size? SizeSkeleton size'large' | 'default' | 'small''default'
loading? StateWhether to show the skeletonbooleantrue
rows? ContentNumber of rows for text variant (only when variant="text" and rows > 1)number1
default? SlotContent to display when loading is complete

Basic Usage

Display skeleton placeholders with different widths.

<template>
  <div class="demo-skeleton">
    <px-skeleton />
    <px-skeleton width="75%" />
    <px-skeleton width="50%" />
  </div>
</template>

<style scoped>
.demo-skeleton {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
</style>

Variants

Use variant to change the skeleton shape: rectangular (default), circular, rounded, or text.

<template>
  <div class="demo-skeleton">
    <div class="demo-skeleton__item">
      <span class="demo-skeleton__label">rectangular</span>
      <px-skeleton variant="rectangular" width="120px" height="80px" />
    </div>
    <div class="demo-skeleton__item">
      <span class="demo-skeleton__label">circular</span>
      <px-skeleton variant="circular" />
    </div>
    <div class="demo-skeleton__item">
      <span class="demo-skeleton__label">rounded</span>
      <px-skeleton variant="rounded" width="120px" height="80px" />
    </div>
    <div class="demo-skeleton__item">
      <span class="demo-skeleton__label">text</span>
      <px-skeleton variant="text" width="200px" />
    </div>
  </div>
</template>

<style scoped>
.demo-skeleton {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 24px;
}
.demo-skeleton__item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}
.demo-skeleton__label {
  font-size: 12px;
  color: var(--vp-c-text-2);
  font-family: var(--px-font-family, monospace);
}
</style>

Animation

Use animated to toggle animation on/off. Use animation to choose the animation style: shimmer (scanline sweep), pulse (two-frame blink), or dither (checkerboard dissolve).

<template>
  <div class="demo-skeleton">
    <div>
      <p class="demo-skeleton__label">shimmer (default)</p>
      <px-skeleton animation="shimmer" width="200px" />
    </div>
    <div>
      <p class="demo-skeleton__label">pulse</p>
      <px-skeleton animation="pulse" width="200px" />
    </div>
    <div>
      <p class="demo-skeleton__label">dither</p>
      <px-skeleton animation="dither" width="200px" />
    </div>
    <div>
      <p class="demo-skeleton__label">static</p>
      <px-skeleton :animated="false" width="200px" />
    </div>
  </div>
</template>

<style scoped>
.demo-skeleton {
  display: flex;
  gap: 32px;
  flex-wrap: wrap;
}
.demo-skeleton__label {
  margin-bottom: 8px;
  font-size: 12px;
  color: var(--vp-c-text-2);
  font-family: var(--px-font-family, monospace);
}
</style>

Loading Toggle

Use loading to switch between skeleton and actual content via the default slot.

<template>
  <div class="demo-skeleton">
    <px-button @click="loading = !loading" size="small">
      {{ loading ? 'Show Content' : 'Show Skeleton' }}
    </px-button>
    <px-skeleton :loading="loading" width="300px">
      <p class="demo-skeleton__content">Content loaded successfully!</p>
    </px-skeleton>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const loading = ref(true);
</script>

<style scoped>
.demo-skeleton {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.demo-skeleton__content {
  margin: 0;
  font-family: var(--px-font-family, monospace);
}
</style>

Text Rows

Use variant="text" with rows to render multiple text lines. The last row is automatically shorter.

<template>
  <div class="demo-skeleton">
    <px-skeleton variant="text" :rows="3" width="300px" />
  </div>
</template>

<style scoped>
.demo-skeleton {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
</style>

Sizes

Use size to set predefined skeleton heights: large, default, or small.

<template>
  <div class="demo-skeleton">
    <div class="demo-skeleton__item">
      <span class="demo-skeleton__label">large</span>
      <px-skeleton size="large" width="200px" />
    </div>
    <div class="demo-skeleton__item">
      <span class="demo-skeleton__label">default</span>
      <px-skeleton width="200px" />
    </div>
    <div class="demo-skeleton__item">
      <span class="demo-skeleton__label">small</span>
      <px-skeleton size="small" width="200px" />
    </div>
  </div>
</template>

<style scoped>
.demo-skeleton {
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.demo-skeleton__item {
  display: flex;
  align-items: center;
  gap: 12px;
}
.demo-skeleton__label {
  font-size: 12px;
  color: var(--vp-c-text-2);
  font-family: var(--px-font-family, monospace);
  min-width: 60px;
}
</style>

Custom Dimensions

Use width and height props for precise control. Numbers are treated as pixels, strings are used as-is.

<template>
  <div class="demo-skeleton">
    <px-skeleton :width="250" :height="40" />
    <px-skeleton width="80%" height="3rem" />
    <px-skeleton variant="circular" :width="64" :height="64" />
  </div>
</template>

<style scoped>
.demo-skeleton {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}
</style>