Overview
Avatar: Avatar placeholder, by default uses Avatar medium sizing:width: 48px,height: 48px. Supports thesizeandshapeproperties; see the API reference for their values.Image: Image placeholder, default size:width: 100%,height: 100%.Title: Title placeholder, default size:width: 100%,height: 24px.Paragraph: Content part placeholder, default size:width: 100%,height: 16px,margin-bottom: 10px.Button: Button placeholder, default size:width: 115px,height: 32px.
Note: Default styles could by overwritten through
classNameorstyle.
Demos
How to import
import { Skeleton } from '@fibrous/semi-ui-react';
Basic Usage
Code
import { useState } from 'react';
import { Skeleton, Switch, Avatar, Button } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const [loading, setLoading] = useState(true);
const showContent = () => {
setLoading(!loading);
};
return (
<>
<span style={{ display: 'flex', alignItems: 'center' }}>
<Switch aria-labelledby="skeleton-basic-toggle" onChange={() => showContent()} />
<span id="skeleton-basic-toggle" style={{ marginLeft: '10px' }}>
显示加载内容
</span>
</span>
<br />
<Skeleton placeholder={<Skeleton.Avatar />} loading={loading}>
<Avatar color="blue" style={{ marginBottom: 10 }}>
U
</Avatar>
</Skeleton>
<br />
<Skeleton style={{ width: 200, height: 150 }} placeholder={<Skeleton.Image />} loading={loading}>
<img src="/assets/placeholder/avatar-a.svg" height="150" alt="avatar" />
</Skeleton>
<br />
<Skeleton style={{ width: 80 }} placeholder={<Skeleton.Title style={{ marginBottom: 10 }} />} loading={loading}>
<h4 style={{ marginBottom: 0 }}>Semi UI</h4>
</Skeleton>
<Skeleton style={{ width: 240 }} placeholder={<Skeleton.Paragraph rows={2} />} loading={loading}>
<p style={{ width: 240 }}>精心打磨每一个组件的用户体验,从用户的角度考虑每个组件的使用场景。</p>
</Skeleton>
<br />
<Skeleton placeholder={<Skeleton.Button />} loading={loading}>
<Button>Button</Button>
</Skeleton>
</>
);
}Combinations
Image and caption.
Code
import { Skeleton } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const placeholder = (
<div>
<Skeleton.Image style={{ width: 200, height: 150 }} />
<Skeleton.Title style={{ width: 120, marginTop: 10 }} />
</div>
);
return (
<Skeleton placeholder={placeholder} loading>
<img src="/assets/placeholder/avatar-a.svg" height="150" alt="avatar" />
<h4>Semi UI</h4>
</Skeleton>
);
}Statistics.
Code
import { Skeleton, Descriptions } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const placeholder = (
<div>
<Skeleton.Paragraph rows={1} style={{ width: 80, marginBottom: 10 }} />
<Skeleton.Title style={{ width: 120 }} />
</div>
);
const data = [{ key: '实际用户数量', value: '1,480,000' }];
return (
<Skeleton placeholder={placeholder} loading>
<Descriptions data={data} row />
</Skeleton>
);
}Avatar and title.
Code
import { Skeleton, Avatar } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const placeholder = (
<div style={{ display: 'flex', alignItems: 'center' }}>
<Skeleton.Avatar style={{ marginRight: 12 }} />
<Skeleton.Title style={{ width: 120 }} />
</div>
);
return (
<Skeleton placeholder={placeholder} loading>
<Avatar color="blue" style={{ marginRight: 12 }}>
UI
</Avatar>
<span>Semi UI</span>
</Skeleton>
);
}Centered paragraphs and button.
Code
import type { CSSProperties } from 'react';
import { Skeleton, Button } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const style: CSSProperties = {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: '300px',
marginBottom: '10px',
};
const placeholder = (
<div style={style}>
<Skeleton.Paragraph style={style} rows={3} />
<Skeleton.Button />
</div>
);
return (
<Skeleton placeholder={placeholder} loading style={{ textAlign: 'center' }}>
<div style={{ textAlign: 'center' }}>
<p>Hi, Bytedance dance dance.</p>
<p>Hi, Bytedance dance dance.</p>
<Button>Button</Button>
</div>
</Skeleton>
);
}Avatar, headline and paragraph.
Code
import { Skeleton, Avatar } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const style = {
display: 'flex',
alignItems: 'flex-start',
};
const placeholder = (
<div style={style}>
<Skeleton.Avatar style={{ marginRight: 12 }} />
<div>
<Skeleton.Title style={{ width: 120, marginBottom: 12, marginTop: 12 }} />
<Skeleton.Paragraph style={{ width: 240 }} rows={3} />
</div>
</div>
);
return (
<Skeleton placeholder={placeholder} loading>
<div style={style}>
<Avatar color="blue" style={{ marginRight: 12 }}>
UI
</Avatar>
<div>
<h3>Semi UI</h3>
<p>Hi, Bytedance dance dance.</p>
<p>Hi, Bytedance dance dance.</p>
<p>Hi, Bytedance dance dance.</p>
</div>
</div>
</Skeleton>
);
}Table.
Code
import type { ReactNode } from 'react';
import { Skeleton, Table, type ColumnProps } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const data = {
columns: [
{
title: 'Name',
dataIndex: 'name',
},
{
title: 'Age',
dataIndex: 'age',
},
{
title: 'Address',
dataIndex: 'address',
},
],
content: [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Disabled User',
age: 99,
address: 'Sidney No. 1 Lake Park',
},
],
};
const skData = {
columns: [1, 2, 3].map((key) => {
const item: ColumnProps = {};
item.title = <Skeleton.Title style={{ width: '0' }} />;
item.dataIndex = `${key}`;
return item;
}),
dataSource: [1, 2, 3, 4].map((key) => {
const item: Record<string, ReactNode> = {};
item.key = key;
[1, 2, 3].forEach((i) => {
const width = 50 * i;
item[i] = <Skeleton.Paragraph style={{ width: width }} rows={1} />;
});
return item;
}),
};
const placeholder = (
<div style={{ position: 'relative' }}>
<Table style={{ backgroundColor: 'var(--semi-color-bg-1)' }} columns={skData.columns} dataSource={skData.dataSource} pagination={false} />
<div style={{ position: 'absolute', left: 0, right: 0, top: 0, bottom: 0 }} />
</div>
);
return (
<Skeleton placeholder={placeholder} loading>
<div>
<Table columns={data.columns} dataSource={data.content} pagination={false} />
</div>
</Skeleton>
);
}Animated Loading
Use active property to display animated loading effects.
Code
import { Skeleton, Avatar } from '@fibrous/semi-ui-react';
export default function SkeletonDemo() {
const style = {
display: 'flex',
alignItems: 'flex-start',
};
const placeholder = (
<div style={style}>
<Skeleton.Avatar style={{ marginRight: 12 }} />
<div>
<Skeleton.Title style={{ width: 120, marginBottom: 12, marginTop: 12 }} />
<Skeleton.Paragraph style={{ width: 240 }} rows={3} />
</div>
</div>
);
return (
<Skeleton placeholder={placeholder} loading active>
<div style={style}>
<Avatar color="blue" style={{ marginRight: 12 }}>
UI
</Avatar>
<div>
<h3>Semi UI</h3>
<p>Hi, Bytedance dance dance.</p>
<p>Hi, Bytedance dance dance.</p>
<p>Hi, Bytedance dance dance.</p>
</div>
</div>
</Skeleton>
);
}API reference
Skeleton
Props
| Property | Description | Type | Default |
|---|---|---|---|
| active | Whether to show the animated loading effect. | boolean | - |
| children | Content shown once loading is false, rendered as is without a wrapper element. | ReactNode | - |
| className | Class name of the placeholder root element. It has no effect once loading is false, since no root element is rendered. | string | - |
| loading | When true, placeholder is shown. Otherwise the children are shown. | boolean | true |
| placeholder | Elements shown while loading. | ReactNode | - |
| ref | Reference to the placeholder root div. It is not attached once loading is false. | TypeReact.Ref<HTMLDivElement> | - |
| style | Style of the placeholder root element. It has no effect once loading is false. | CSSProperties | - |
Other native attributes (such as id, aria-* and events) fall through onto the placeholder root div. When loading is false the component renders only the children and has no root element, so these are dropped together with the placeholder. The root's aria-busy="true" cannot be switched off.
Skeleton.Avatar
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the avatar placeholder. | string | - |
| prefixCls | Class name prefix, semi-skeleton by default. | string | - |
| ref | Reference to the avatar placeholder. | TypeReact.Ref<HTMLDivElement> | - |
| shape | Shape of the avatar placeholder: circle or square. Defaults to circle. | 'circle' | 'square' | - |
| size | Size of the avatar placeholder: extra-extra-small, extra-small, small, medium, large or extra-large. Defaults to medium. | Type'extra-extra-small' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large' | - |
| style | Style of the avatar placeholder. | CSSProperties | - |
| type | Replaces the type of the block, which also names its class. Unless it is avatar, size and shape have no effect. | string | - |
Other native attributes (such as id, aria-* and events) fall through onto the placeholder block; an aria-hidden passed by the caller takes precedence over the block's aria-hidden="true".
Skeleton.Image
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the image placeholder. | string | - |
| prefixCls | Class name prefix, semi-skeleton by default. | string | - |
| ref | Reference to the image placeholder. | TypeReact.Ref<HTMLDivElement> | - |
| style | Style of the image placeholder. | CSSProperties | - |
| type | Replaces the type of the block, which also names its class. | string | - |
Skeleton.Title
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the title placeholder. | string | - |
| prefixCls | Class name prefix, semi-skeleton by default. | string | - |
| ref | Reference to the title placeholder. | TypeReact.Ref<HTMLDivElement> | - |
| style | Style of the title placeholder. | CSSProperties | - |
| type | Replaces the type of the block, which also names its class. | string | - |
Skeleton.Button
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the button placeholder. | string | - |
| prefixCls | Class name prefix, semi-skeleton by default. | string | - |
| ref | Reference to the button placeholder. | TypeReact.Ref<HTMLDivElement> | - |
| style | Style of the button placeholder. | CSSProperties | - |
| type | Replaces the type of the block, which also names its class. | string | - |
Skeleton.Image, Skeleton.Title and Skeleton.Button have no size or shape; other native attributes fall through onto the placeholder block as well.
Skeleton.Paragraph
Props
| Property | Description | Type | Default |
|---|---|---|---|
| prefixCls | Class name prefix. | string | "semi-skeleton" |
| ref | Reference to the root ul element of the paragraph placeholder. | TypeReact.Ref<HTMLUListElement> | - |
| rows | Number of rows in the placeholder paragraph, each rendered as an li. | number | 4 |
className, style and native attributes fall through onto the root ul element.
Accessibility
- While loading, the outer element of Skeleton carries
aria-busy="true", and the placeholder blocks and paragraph carryaria-hidden="true", so screen readers only know that content is loading. Anaria-hiddenpassed by the caller takes precedence on a placeholder block;aria-busycannot be switched off. - Once loading ends, the children are rendered directly and Skeleton adds no outer element.
Content Guidelines
- Unchanged fixed content directly displays fixed content, and variable content is displayed using skeleton screen
Design Tokens
| Sass variable | Value | Usage |
|---|---|---|
| $animation_duration-skeleton-highlight | 1400ms | 骨架屏高亮动画时长 |
| $animation_function-skeleton-highlight | ease | |
| $color-skeleton_default-bg-default | var(--semi-color-fill-0) | 骨架屏背景色 - 默认 |
| $color-skeleton_loading-gradient-bg-active | var(--semi-color-fill-1) | 骨架屏背景色 - 动画开启后 |
| $width-skeleton_avatar_extra_extra_small | 20px | 头像骨架屏尺寸 - 极小 |
| $width-skeleton_avatar_extra_small | 24px | 头像骨架屏尺寸 - 超小 |
| $width-skeleton_avatar_small | 32px | 头像骨架屏尺寸 - 小 |
| $width-skeleton_avatar_medium | 48px | 头像骨架屏尺寸 - 中 |
| $width-skeleton_avatar_large | 72px | 头像骨架屏尺寸 - 大 |
| $width-skeleton_avatar_extra_large | 128px | 头像骨架屏尺寸 - 超大 |
| $width-skeleton_button | 115px | 按钮骨架屏宽度 |
| $height-skeleton_li | 16px | 段落骨架屏高度 |
| $height-skeleton_title | $height-control-small | 标题骨架屏高度 |
| $height-skeleton_button | $height-control-default | 按钮骨架屏高度 |
| $spacing-skeleton_li-marginBottom | 10px | 按钮骨架屏高度 |
| $radius-skeleton_item | var(--semi-border-radius-small) | 骨架屏圆角 |
| $radius-skeleton_li | var(--semi-border-radius-small) | 骨架屏圆角 |