Skeleton
A skeleton stands in for content that has not arrived, in roughly the shape it will arrive in. It supplies the fill and the animation and nothing else — the shape is yours, given with classes, so one component covers an avatar, a headline and a thumbnail.
import { Skeleton } from "ropav";<Skeleton class="h-24 w-64 rounded-xl" />In the shape of the thing
skeleton-card.vue
<script setup lang="ts">
import { Card, Skeleton } from "ropav";
</script>
<template>
<Card class="card">
<Skeleton class="thumb" />
<div class="lines">
<Skeleton class="line line--short" />
<Skeleton class="line line--long" />
<Skeleton class="line line--stub" />
</div>
</Card>
</template>
<style scoped>
.card {
display: flex;
width: calc(var(--rp-spacing) * 56);
flex-direction: column;
gap: calc(var(--rp-spacing) * 5);
}
.thumb {
height: calc(var(--rp-spacing) * 24);
border-radius: calc(var(--rp-radius) * 1.5);
}
.lines {
display: flex;
flex-direction: column;
gap: calc(var(--rp-spacing) * 3);
}
.line.line--short {
height: calc(var(--rp-spacing) * 3);
width: 60%;
border-radius: var(--rp-radius);
}
.line.line--long {
height: calc(var(--rp-spacing) * 3);
width: 80%;
border-radius: var(--rp-radius);
}
.line.line--stub {
height: calc(var(--rp-spacing) * 3);
width: 40%;
border-radius: var(--rp-radius);
}
</style>A skeleton that does not resemble what replaces it is worse than none: the layout shifts when the content lands, and the reader has been shown a shape that turned out to be a lie.
The animation is a theme decision
animation-type is an override. Left unset, the skeleton reads --rp-skeleton-animation from the theme, so a theme can settle on pulse or turn the animation off across a whole application without a prop being passed anywhere.
For one shimmer travelling across a group rather than one per placeholder, put the shimmer class on the container. A container carrying it that has skeletons inside runs a single pass over all of them and stops each child's own:
<div class="rp-skeleton--shimmer relative grid grid-cols-3 gap-4 overflow-hidden rounded-[calc(var(--rp-radius)*1.5)]">
<Skeleton class="h-24 rounded-[calc(var(--rp-radius)*1.5)]" />
<Skeleton class="h-24 rounded-[calc(var(--rp-radius)*1.5)]" />
<Skeleton class="h-24 rounded-[calc(var(--rp-radius)*1.5)]" />
</div>Accessibility
- A skeleton says nothing to a screen reader, which is the right answer for a decoration standing in for content. Announce the wait itself where it matters — a
role="status"on the region, or a Spinner, says a load is in progress in a way a shape cannot. - Under Forced Colors Mode the fill flattens to the page colour and the shimmer is dropped outright, so the placeholder is given an inset outline instead — otherwise it would vanish.
- Neither animation is turned off for a reader who has asked for reduced motion. Setting
--rp-skeleton-animation: nonein the theme is how to answer that across an application.
API
| Prop | Type | Default | Description |
|---|---|---|---|
animationType | "shimmer" | "pulse" | "none" | — | Animation type. Falls back to the theme's --rp-skeleton-animation value. |
Slots: default.