Loading Skeleton Set
Free · MITShimmer skeleton placeholders for text lines, an avatar row, a card, and a table row, with the shimmer disabled under reduced motion.
- Category
- Core UI
- Framework
- astro
- Version
- 1.0.0
- Peer deps
- none
Install
velocityx add loading-skeleton
Free and MIT licensed — no account needed. The file lands under src/components/velocity/loading-skeleton/ by default (override with --dest), and it's yours to edit from the moment it's written.
Demo
View the live demo on the showcase site ↗
Source
Pulled live from the registry — this is the exact file velocityx add loading-skeleton writes into your project right now.
components/velocity/loading-skeleton/LoadingSkeleton.astro
---
// VELOCITY COMPONENT · theming
//
// Colours here are Tailwind `primary-*` / `accent-*`, which resolve through
// the Velocity preset. Out of the box they are a neutral indigo — NOT the
// Aidxn brand — so this drops into your project without dragging our look in.
//
// ⚡ NOT USING VELOCITY? Run this once, in your project root:
//
// velocityx theme
//
// It writes velocity-preset.cjs + velocity-theme.css. Add the preset to your
// tailwind.config, import the css, then set your whole brand in ONE place:
//
// :root {
// --vx-brand: custom;
// --vx-primary-600: 220 38 38; <- your action colour
// --vx-primary-700: 185 28 28;
// }
//
// ⚠️ Raw RGB channels, space separated — NOT hex. `#DC2626` here silently
// breaks every /opacity variant in the library (bg-primary-600/20 etc).
//
// Prefer not to install anything? Find-and-replace `primary-` with your own
// scale name. Nothing else in this file depends on Velocity.
/**
* LoadingSkeleton — shimmer placeholder set: text lines, avatar, card, table
* row. Pick a `shape`, or compose your own from `.v-skel` directly. Shimmer
* is a CSS gradient sweep (no JS), disabled under prefers-reduced-motion in
* favour of a static tint.
*
* Usage:
* <LoadingSkeleton shape="text" lines={3} />
* <LoadingSkeleton shape="card" />
* <LoadingSkeleton shape="avatar-line" />
* <LoadingSkeleton shape="table-row" columns={4} />
*/
export interface Props {
shape?: 'text' | 'avatar-line' | 'card' | 'table-row';
lines?: number;
columns?: number;
}
const { shape = 'text', lines = 3, columns = 4 } = Astro.props;
---
<style>
.v-skel {
position: relative;
overflow: hidden;
background-color: theme('colors.secondary.150', theme('colors.secondary.100'));
}
:global(.dark) .v-skel { background-color: theme('colors.secondary.800'); }
.v-skel::after {
content: '';
position: absolute;
inset: 0;
transform: translateX(-100%);
background-image: linear-gradient(90deg, transparent, rgba(255,255,255,0.45), transparent);
animation: v-skel-sweep 1.6s ease-in-out infinite;
}
:global(.dark) .v-skel::after {
background-image: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent);
}
@media (prefers-reduced-motion: reduce) {
.v-skel::after { animation: none; display: none; }
}
@keyframes v-skel-sweep {
100% { transform: translateX(100%); }
}
</style>
<div role="status" aria-label="Loading" class="animate-none">
{shape === 'text' && (
<div class="flex flex-col gap-2.5">
{Array.from({ length: lines }).map((_, i) => (
<div class:list={['v-skel h-3 rounded-full', i === lines - 1 ? 'w-2/3' : 'w-full']} />
))}
</div>
)}
{shape === 'avatar-line' && (
<div class="flex items-center gap-3">
<div class="v-skel h-10 w-10 rounded-full shrink-0" />
<div class="flex-1 flex flex-col gap-2">
<div class="v-skel h-3 w-1/3 rounded-full" />
<div class="v-skel h-2.5 w-1/2 rounded-full" />
</div>
</div>
)}
{shape === 'card' && (
<div class="rounded-2xl border border-secondary-200 dark:border-secondary-800 p-4">
<div class="v-skel aspect-video w-full rounded-xl mb-4" />
<div class="v-skel h-3 w-3/4 rounded-full mb-2" />
<div class="v-skel h-2.5 w-1/2 rounded-full" />
</div>
)}
{shape === 'table-row' && (
<div class="flex items-center gap-4 py-3">
{Array.from({ length: columns }).map(() => (
<div class="v-skel h-3 flex-1 rounded-full" />
))}
</div>
)}
<span class="sr-only">Loading…</span>
</div>
Theming
Uses the shared primary-* / accent-* scale — see Theming if colours look unstyled after install.