Skip to content

Skeleton ​

17:06

Description ​

A placeholder skeleton shown while data loads. With loading=true it renders gray blocks per avatar / title / rows; with loading=false it renders the real content from the default slot, replacing in place; animate controls the per-block shimmer.

Compatibility ​

PlatformSupport
App✅ Supported (shimmer is driven by UniElement.animate per block, with a simplified two-stop gradient)
H5✅ Supported (shimmer is driven by CSS @keyframes)
WeChat Mini Program✅ Supported (shimmer is driven by CSS @keyframes)

Examples ​

Basic Usage ​

Shows title and paragraph placeholders by default when loading=true.

View source
vue
<template>
    <ux-skeleton :loading="true" :rows="3" />
</template>

Rows (rows) ​

Set the number of paragraph placeholder rows via rows.

View source
vue
<template>
    <ux-skeleton :loading="true" :rows="rows" />
    <view class="btn-wrap">
        <ux-button v-for="(item, index) in rowsList" :key="index" :type="rows === item.value ? 'primary' : 'default'" custom-class="btn-item" @click="rows = item.value">{{ item.label }}</ux-button>
    </view>
</template>

<script setup lang="uts">
const rows = ref<number>(3);

const rowsList = [
    { value: 2, label: '2' },
    { value: 3, label: '3' },
    { value: 5, label: '5' }
];
</script>

<style scoped>
.btn-wrap {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    margin-top: 10px;
}
.btn-item {
    margin-right: 12px;
}
</style>

Custom Width/Height ​

rows-width / rows-height support arrays per row; title-width / title-height set the title size.

View source
vue
<template>
    <ux-skeleton :loading="true" :rows="3" :rows-width="['100%', '80%', '60%']" :rows-height="['25', '25', '25']" :title-width="'40%'" :title-height='30' />
</template>

Avatar (avatar) ​

avatar=true shows an avatar placeholder; avatar-shape supports circle / square.

View source
vue
<template>
    <ux-skeleton :loading="true" :rows="3" avatar :avatar-size="20" avatar-shape="circle" />
</template>

Animation Toggle (animate) ​

animate controls the shimmer sweep; toggle the button to compare on/off.

View source
vue
<template>
    <ux-skeleton :loading="true" :rows="3" :animate="animate" />
    <view class="btn-wrap">
        <ux-button :type="animate ? 'primary' : 'default'" @click="animate = !animate">{{ animate ? '开启动画' : '关闭动画' }}</ux-button>
    </view>
</template>

<script setup lang="uts">
const animate = ref<boolean>(true);
</script>

<style scoped>
.btn-wrap {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    margin-top: 10px;
}
</style>

List Scene ​

Simulates message/article list skeletons; each card shimmers independently for a realistic look.

View source
vue
<template>
    <view class="list">
        <ux-skeleton v-for="(item, index) in sceneList" :key="index" custom-class="list-item" avatar title :rows="3" :rows-width="['100%', '90%', '62%']" :rows-height="['16', '16', '16']" :title-width="'32%'" :title-height="'22'" />
    </view>
</template>

<script setup lang="uts">
const sceneList = [1, 2, 3];
</script>

<style scoped>
.list {
    display: flex;
    flex-direction: column;
}
.list-item {
    margin-bottom: 12px;
    padding: 14px;
    background-color: #ffffff;
    border-radius: 8px;
}
</style>

Loaded (loading) ​

loading=false hides the skeleton and shows real content; the skeleton structure matches the real content one-to-one and replaces it in place.

View source
vue
<template>
    <ux-skeleton :loading="loading" title avatar :rows="3" :rows-height="['18', '18', '40']" :title-height="'22'">
        <view class="card">
            <view class="card__avatar"></view>
            <view class="card__body">
                <text class="card__title">uView Pro 组件库</text>
                <text class="card__line">丰富的组件覆盖开发过程各类需求,多端兼容,开箱即用。</text>
                <text class="card__line">组件功能完善,样式与全局主题均支持自定义。</text>
                <text class="card__line">示例代码一键复制,快速集成进你的项目。</text>
            </view>
        </view>
    </ux-skeleton>
    <view class="wrap">
        <ux-button :type="loading ? 'primary' : 'default'" shape="round" @click="loading = !loading">{{ loading ? '切换加载中' : '加载完成' }}</ux-button>
    </view>
</template>

<script setup lang="uts">
const loading = ref<boolean>(true);
</script>

<style scoped>
.wrap {
    display: flex;
    flex-direction: row;
    margin-top: 10px;
}
.card {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    width: 100%;
    padding: 12px;
    background-color: #ffffff;
    border-radius: 8px;
}
.card__avatar {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background-color: #2979ff;
    margin-right: 12px;
    flex-shrink: 0;
}
.card__body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    flex: 1;
}
.card__title {
    font-size: 16px;
    font-weight: bold;
    color: #323233;
    margin-bottom: 8px;
}
.card__line {
    font-size: 13px;
    line-height: 20px;
    color: #606266;
    margin-bottom: 4px;
}
</style>

API ​

Props ​

PropertyDescriptionTypeDefaultVersion
customStyleCustom root element stylestring | UTSJSONObject--
customClassCustom root element style classstring''-
loadingWhether to show the skeleton placeholdersbooleantrue-
animateWhether to enable the shimmer animationbooleantrue-
rowsNumber of paragraph placeholder rowsstring | number0-
rowsWidthWidth of the paragraph placeholdersstring | number | string[]'100%'-
rowsHeightHeight of the paragraph placeholdersstring | number | string[]18-
titleWhether to show the title placeholderbooleantrue-
titleWidthWidth of the titlestring | number'50%'-
titleHeightHeight of the titlestring | number18-
avatarWhether to show the avatar placeholderbooleanfalse-
avatarSizeSize of the avatar placeholderstring | number32-
avatarShapeShape of the avatar placeholderstring'circle'-

Events ​

ux-skeleton has no events.

Slots ​

SlotDescriptionVersion
defaultReal content shown when loading=false-

Notes ​

  • The default slot is rendered only when loading=false; keep the skeleton and the real content structurally consistent, or the switch will jump.
  • When rows-width / rows-height are arrays they are read by row index; if the array is shorter, the width falls back to 70% for the last row and 100% for the rest, and the height falls back to 18.
  • animate is only visible while loading=true; the shimmer is clipped inside each placeholder block (overflow: hidden) and does not bleed into the gaps between blocks.
  • On App, @keyframes is not used — the shimmer is driven by UniElement.animate per block, and linear-gradient only supports a direction plus two colors, so the gradient is simpler than on H5 / Mini Program.
  • avatar-shape supports circle (default) and square (a 4px small radius).