UISkeleton
UISkeleton
A versatile skeleton loading component that provides animated placeholders for content that is being loaded, with support for various shapes, sizes, and animations.
<template> <UISkeleton :rows="3" :animate="true" :variant="'rounded'" class="w-full max-w-md" > <template #header> <div class="flex items-center space-x-4"> <UISkeleton.Circle size="48" /> <div class="space-y-2 flex-1"> <UISkeleton.Line width="60%" /> <UISkeleton.Line width="40%" /> </div> </div> </template>
<template #footer> <div class="flex justify-between mt-4"> <UISkeleton.Line width="30%" /> <UISkeleton.Line width="20%" /> </div> </template> </UISkeleton></template>Props
rows(number): Number of skeleton rowsanimate(boolean): Enable animationvariant(string): Visual variantheight(string | number): Row heightwidth(string | number): Component widthspeed(string): Animation speeddark(boolean): Dark mode variantrounded(boolean): Use rounded cornerscircle(boolean): Circular shapepreserveAspectRatio(boolean): Maintain aspect ratio
Slots
default: Main content areaheader: Content before rowsfooter: Content after rows
Usage Examples
- Basic Loading State:
<template> <UISkeleton :rows="3" class="max-w-sm"> <template #header> <UISkeleton.Line width="70%" class="mb-4" /> </template> </UISkeleton></template>- Card Loading State:
<template> <div class="grid gap-4 grid-cols-3"> <div v-for="n in 3" :key="n" class="p-4 border rounded-lg" > <UISkeleton animate> <template #header> <div class="flex items-center space-x-3 mb-4"> <UISkeleton.Circle size="40" /> <div class="space-y-2 flex-1"> <UISkeleton.Line width="70%" /> <UISkeleton.Line width="40%" /> </div> </div> </template>
<UISkeleton.Line class="mb-2" /> <UISkeleton.Line width="90%" class="mb-2" /> <UISkeleton.Line width="80%" />
<template #footer> <div class="flex justify-between mt-4"> <UISkeleton.Line width="30%" /> <UISkeleton.Line width="20%" /> </div> </template> </UISkeleton> </div> </div></template>- Table Loading State:
<template> <div class="border rounded-lg overflow-hidden"> <div class="bg-gray-50 p-4"> <UISkeleton.Line width="30%" /> </div>
<div class="divide-y"> <div v-for="n in 5" :key="n" class="p-4" > <UISkeleton animate> <div class="flex items-center justify-between"> <div class="flex items-center space-x-4"> <UISkeleton.Circle size="32" /> <div class="space-y-2"> <UISkeleton.Line width="120px" /> <UISkeleton.Line width="80px" /> </div> </div>
<div class="flex space-x-4"> <UISkeleton.Line width="60px" /> <UISkeleton.Line width="40px" /> </div> </div> </UISkeleton> </div> </div> </div></template>Best Practices
-
Visual Design:
- Match content structure
- Consistent sizing
- Appropriate spacing
- Realistic proportions
-
Animation:
- Subtle animations
- Consistent timing
- Smooth transitions
- Performance optimization
-
Accessibility:
- ARIA live regions
- Loading indicators
- Screen reader support
- Focus management
-
Implementation:
- Reusable patterns
- Component composition
- Responsive design
- Performance considerations
Common Use Cases
- List Loading:
<template> <div class="space-y-4"> <UISkeleton v-for="n in 5" :key="n" animate > <div class="flex items-center space-x-4"> <UISkeleton.Circle size="48" /> <div class="space-y-2 flex-1"> <UISkeleton.Line width="40%" /> <UISkeleton.Line width="70%" /> <UISkeleton.Line width="30%" /> </div> </div> </UISkeleton> </div></template>- Dashboard Loading:
<template> <div class="grid gap-6 grid-cols-1 md:grid-cols-3"> <!-- Stats Cards --> <div v-for="n in 3" :key="n" class="p-6 bg-white rounded-lg shadow-sm" > <UISkeleton animate> <UISkeleton.Line width="40%" class="mb-4" /> <UISkeleton.Line width="60%" height="32px" class="mb-2" /> <UISkeleton.Line width="30%" /> </UISkeleton> </div>
<!-- Chart --> <div class="md:col-span-2 p-6 bg-white rounded-lg shadow-sm"> <UISkeleton animate> <UISkeleton.Line width="30%" class="mb-6" /> <UISkeleton.Rectangle height="200px" class="mb-4" /> <div class="flex justify-between"> <UISkeleton.Line width="15%" /> <UISkeleton.Line width="15%" /> <UISkeleton.Line width="15%" /> </div> </UISkeleton> </div>
<!-- Activity List --> <div class="md:col-span-1 p-6 bg-white rounded-lg shadow-sm"> <UISkeleton animate> <UISkeleton.Line width="50%" class="mb-4" /> <div class="space-y-4"> <div v-for="n in 4" :key="n" class="flex items-center space-x-3" > <UISkeleton.Circle size="32" /> <div class="space-y-1 flex-1"> <UISkeleton.Line width="60%" /> <UISkeleton.Line width="40%" /> </div> </div> </div> </UISkeleton> </div> </div></template>- Form Loading:
<template> <div class="max-w-lg space-y-6"> <UISkeleton animate> <div class="space-y-4"> <!-- Form Header --> <UISkeleton.Line width="60%" height="32px" class="mb-6" />
<!-- Form Fields --> <div v-for="n in 3" :key="n" class="space-y-2" > <UISkeleton.Line width="30%" /> <UISkeleton.Rectangle height="40px" class="rounded" /> </div>
<!-- Form Footer --> <div class="flex justify-end space-x-4 mt-8"> <UISkeleton.Rectangle width="100px" height="40px" class="rounded" /> <UISkeleton.Rectangle width="100px" height="40px" class="rounded" /> </div> </div> </UISkeleton> </div></template>Component Composition
The UISkeleton component can be composed with other components to create complex loading states:
<template> <div class="space-y-6"> <!-- Header --> <UISkeleton animate> <div class="flex items-center justify-between"> <div class="space-y-2"> <UISkeleton.Line width="200px" height="32px" /> <UISkeleton.Line width="160px" /> </div>
<UISkeleton.Rectangle width="120px" height="40px" class="rounded" /> </div> </UISkeleton>
<!-- Filters --> <UISkeleton animate> <div class="flex space-x-4"> <UISkeleton.Rectangle v-for="n in 3" :key="n" width="120px" height="36px" class="rounded" /> </div> </UISkeleton>
<!-- Content --> <UISkeleton :rows="5" animate class="rounded-lg border p-4" > <template #header> <div class="flex justify-between mb-4"> <UISkeleton.Line width="30%" /> <UISkeleton.Line width="20%" /> </div> </template> </UISkeleton>
<!-- Pagination --> <UISkeleton animate> <div class="flex justify-between items-center"> <UISkeleton.Line width="100px" /> <div class="flex space-x-2"> <UISkeleton.Rectangle v-for="n in 4" :key="n" width="36px" height="36px" class="rounded" /> </div> </div> </UISkeleton> </div></template>