Skip to content

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 rows
  • animate (boolean): Enable animation
  • variant (string): Visual variant
  • height (string | number): Row height
  • width (string | number): Component width
  • speed (string): Animation speed
  • dark (boolean): Dark mode variant
  • rounded (boolean): Use rounded corners
  • circle (boolean): Circular shape
  • preserveAspectRatio (boolean): Maintain aspect ratio

Slots

  • default: Main content area
  • header: Content before rows
  • footer: Content after rows

Usage Examples

  1. Basic Loading State:
<template>
<UISkeleton :rows="3" class="max-w-sm">
<template #header>
<UISkeleton.Line width="70%" class="mb-4" />
</template>
</UISkeleton>
</template>
  1. 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>
  1. 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

  1. Visual Design:

    • Match content structure
    • Consistent sizing
    • Appropriate spacing
    • Realistic proportions
  2. Animation:

    • Subtle animations
    • Consistent timing
    • Smooth transitions
    • Performance optimization
  3. Accessibility:

    • ARIA live regions
    • Loading indicators
    • Screen reader support
    • Focus management
  4. Implementation:

    • Reusable patterns
    • Component composition
    • Responsive design
    • Performance considerations

Common Use Cases

  1. 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>
  1. 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>
  1. 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>