Skeleton
Placeholder preview before content loads. Placeholder blocks are aria-hidden from screen readers; the container signals state via aria-busy and aria-live. The pulse animation respects prefers-reduced-motion.
Basic Usage
Basic Usage
vue
<script setup lang="ts">
import { ref } from 'vue'
const skeletonLoading = ref(true)
</script>
<template>
<!-- Basic Usage -->
<LhSkeleton :rows="3" :loading="skeletonLoading">
<p>Content loaded.</p>
</LhSkeleton>
<!-- Toggle loading -->
<LhButton size="small" @click="skeletonLoading = !skeletonLoading">
{{ skeletonLoading ? 'Show content' : 'Show skeleton' }}
</LhButton>
</template>vue
<script>
export default {
data() {
return { skeletonLoading: true }
},
}
</script>
<template>
<!-- Basic Usage -->
<LhSkeleton :rows="3" :loading="skeletonLoading">
<p>Content loaded.</p>
</LhSkeleton>
<!-- Toggle loading -->
<LhButton size="small" @click="skeletonLoading = !skeletonLoading">
{{ skeletonLoading ? 'Show content' : 'Show skeleton' }}
</LhButton>
</template>With Avatar
With Avatar
vue
<script setup lang="ts">
</script>
<template>
<LhSkeleton avatar :rows="2" />
</template>vue
<script>
export default {}
</script>
<template>
<LhSkeleton avatar :rows="2" />
</template>Without Animation
Static
vue
<script setup lang="ts">
</script>
<template>
<LhSkeleton :rows="3" :animated="false" />
</template>vue
<script>
export default {}
</script>
<template>
<LhSkeleton :rows="3" :animated="false" />
</template>SkeletonItem
SkeletonItem
vue
<script setup lang="ts">
</script>
<template>
<LhSkeletonItem variant="circle" />
<LhSkeletonItem variant="rect" style="width: 120px; height: 60px" />
</template>vue
<script>
export default {}
</script>
<template>
<LhSkeletonItem variant="circle" />
<LhSkeletonItem variant="rect" style="width: 120px; height: 60px" />
</template>Skeleton API
Props
| Prop | Description | Type | Default |
|---|---|---|---|
| loading | Loading state (false renders the default slot) | boolean | true |
| rows | Number of text rows | number | 3 |
| avatar | Include a circle avatar placeholder | boolean | false |
| animated | Enable the pulse animation | boolean | true |
| sx | sx quick-layout properties | LhSxProps | — |
Slots
| Slot | Description |
|---|---|
| default | Real content rendered when loading is false |
SkeletonItem API
Props
| Prop | Description | Type | Default |
|---|---|---|---|
| variant | Placeholder shape | 'text' | 'rect' | 'circle' | 'text' |
| animated | Enable the pulse animation | boolean | true |
| sx | sx quick-layout properties | LhSxProps | — |
Theme Variables
| Variable | Description | Default |
|---|---|---|
--lh-skeleton-bg | Placeholder base color | Ink tone (text-regular) at 10% opacity |
--lh-skeleton-highlight | Shimmer highlight color | Base color lightened 45% toward white |
--lh-skeleton-radius | Base radius | --lh-border-radius-small |
Accessibility
- Placeholders are
aria-hidden="true"and skipped by screen readers - Container has
aria-busy="true"+aria-live="polite"— the content swap is announced - The pulse animation is disabled under
prefers-reduced-motion: reduce
Type Definitions
The TypeScript type structures exported by this component (auto-extracted from packages/components/skeleton/src/types.ts and @lh-ui/share/core/* sources; click each entry to expand; see the Props table above for attribute descriptions):
LhSkeletonProps
ts
export interface LhSkeletonProps {
loading?: boolean
rows?: number
avatar?: boolean
animated?: boolean
sx?: LhSxProps
}LhSkeletonItemProps
ts
export interface LhSkeletonItemProps {
variant?: LhSkeletonVariant
animated?: boolean
sx?: LhSxProps
}LhSkeletonVariant (from @lh-ui/share/core/skeleton)
ts
export type LhSkeletonVariant = 'text' | 'rect' | 'circle'