Skeleton

Provide a placeholder while you wait for content to load, or to visualise content that doesn't exist yet.

When To Use#

  • When a resource needs long time to load.

  • When the component contains lots of information, such as List or Card.

  • Only works when loading data for the first time.

  • Could be replaced by Spin in any situation, but can provide a better user experience.

Examples

Simplest Skeleton usage.

expand codeexpand code
import { Skeleton } from 'antd';

ReactDOM.render(<Skeleton />, mountNode);

Complex combination with avatar and multiple paragraphs.

expand codeexpand code
import { Skeleton } from 'antd';

ReactDOM.render(<Skeleton avatar paragraph={{ rows: 4 }} />, mountNode);

Display active animation.

expand codeexpand code
import { Skeleton } from 'antd';

ReactDOM.render(<Skeleton active />, mountNode);


Skeleton button, avatar and input.

expand codeexpand code
import { Skeleton, Switch, Form, Radio } from 'antd';

class Demo extends React.Component {
  state = {
    buttonActive: false,
    avatarActive: false,
    inputActive: false,
    buttonSize: 'default',
    avatarSize: 'default',
    inputSize: 'default',
    buttonShape: 'default',
    avatarShape: 'circle',
  };

  handleActiveChange = prop => checked => {
    this.setState({ [prop]: checked });
  };

  handleSizeChange = prop => e => {
    this.setState({ [prop]: e.target.value });
  };

  handleShapeChange = prop => e => {
    this.setState({ [prop]: e.target.value });
  };

  render() {
    const {
      buttonActive,
      avatarActive,
      inputActive,
      buttonSize,
      avatarSize,
      inputSize,
      buttonShape,
      avatarShape,
    } = this.state;
    return (
      <div>
        <div>
          <Form layout="inline" style={{ marginBottom: 16 }}>
            <Form.Item label="ButtonActive">
              <Switch checked={buttonActive} onChange={this.handleActiveChange('buttonActive')} />
            </Form.Item>
            <Form.Item label="ButtonSize">
              <Radio.Group value={buttonSize} onChange={this.handleSizeChange('buttonSize')}>
                <Radio.Button value="default">Default</Radio.Button>
                <Radio.Button value="large">Large</Radio.Button>
                <Radio.Button value="small">Small</Radio.Button>
              </Radio.Group>
            </Form.Item>
            <Form.Item label="ButtonShape">
              <Radio.Group value={buttonShape} onChange={this.handleShapeChange('buttonShape')}>
                <Radio.Button value="default">Default</Radio.Button>
                <Radio.Button value="round">Round</Radio.Button>
                <Radio.Button value="circle">Circle</Radio.Button>
              </Radio.Group>
            </Form.Item>
          </Form>
          <Skeleton.Button active={buttonActive} size={buttonSize} shape={buttonShape} />
        </div>
        <br />
        <div>
          <Form layout="inline" style={{ marginBottom: 16 }}>
            <Form.Item label="AvatarActive">
              <Switch checked={avatarActive} onChange={this.handleActiveChange('avatarActive')} />
            </Form.Item>
            <Form.Item label="AvatarSize">
              <Radio.Group value={avatarSize} onChange={this.handleSizeChange('avatarSize')}>
                <Radio.Button value="default">Default</Radio.Button>
                <Radio.Button value="large">Large</Radio.Button>
                <Radio.Button value="small">Small</Radio.Button>
              </Radio.Group>
            </Form.Item>
            <Form.Item label="AvatarShape">
              <Radio.Group value={avatarShape} onChange={this.handleShapeChange('avatarShape')}>
                <Radio.Button value="square">Square</Radio.Button>
                <Radio.Button value="circle">Circle</Radio.Button>
              </Radio.Group>
            </Form.Item>
          </Form>
          <Skeleton.Avatar active={avatarActive} size={avatarSize} shape={avatarShape} />
        </div>
        <br />
        <div>
          <Form layout="inline" style={{ marginBottom: 16 }}>
            <Form.Item label="InputActive">
              <Switch checked={inputActive} onChange={this.handleActiveChange('inputActive')} />
            </Form.Item>
            <Form.Item label="InputSize">
              <Radio.Group value={inputSize} onChange={this.handleSizeChange('inputSize')}>
                <Radio.Button value="default">Default</Radio.Button>
                <Radio.Button value="large">Large</Radio.Button>
                <Radio.Button value="small">Small</Radio.Button>
              </Radio.Group>
            </Form.Item>
          </Form>
          <Skeleton.Input style={{ width: '300px' }} active={inputActive} size={inputSize} />
        </div>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, mountNode);

Ant Design, a design language

We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.

Skeleton contains sub component.

expand codeexpand code
import { Skeleton, Button } from 'antd';

class Demo extends React.Component {
  state = {
    loading: false,
  };

  showSkeleton = () => {
    this.setState({ loading: true });
    setTimeout(() => {
      this.setState({ loading: false });
    }, 3000);
  };

  render() {
    return (
      <div className="article">
        <Skeleton loading={this.state.loading}>
          <div>
            <h4>Ant Design, a design language</h4>
            <p>
              We supply a series of design principles, practical patterns and high quality design
              resources (Sketch and Axure), to help people create their product prototypes
              beautifully and efficiently.
            </p>
          </div>
        </Skeleton>
        <Button onClick={this.showSkeleton} disabled={this.state.loading}>
          Show Skeleton
        </Button>
      </div>
    );
  }
}

ReactDOM.render(<Demo />, mountNode);

Use skeleton in list component.

expand codeexpand code
import { Skeleton, Switch, List, Avatar } from 'antd';
import { StarOutlined, LikeOutlined, MessageOutlined } from '@ant-design/icons';

const listData = [];
for (let i = 0; i < 3; i++) {
  listData.push({
    href: 'http://ant.design',
    title: `ant design part ${i}`,
    avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
    description:
      'Ant Design, a design language for background applications, is refined by Ant UED Team.',
    content:
      'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',
  });
}

const IconText = ({ icon, text }) => (
  <span>
    {React.createElement(icon, { style: { marginRight: 8 } })}
    {text}
  </span>
);

class App extends React.Component {
  state = {
    loading: true,
  };

  onChange = checked => {
    this.setState({ loading: !checked });
  };

  render() {
    const { loading } = this.state;

    return (
      <div>
        <Switch checked={!loading} onChange={this.onChange} />

        <List
          itemLayout="vertical"
          size="large"
          dataSource={listData}
          renderItem={item => (
            <List.Item
              key={item.title}
              actions={
                !loading && [
                  <IconText icon={StarOutlined} text="156" key="list-vertical-star-o" />,
                  <IconText icon={LikeOutlined} text="156" key="list-vertical-like-o" />,
                  <IconText icon={MessageOutlined} text="2" key="list-vertical-message" />,
                ]
              }
              extra={
                !loading && (
                  <img
                    width={272}
                    alt="logo"
                    src="https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png"
                  />
                )
              }
            >
              <Skeleton loading={loading} active avatar>
                <List.Item.Meta
                  avatar={<Avatar src={item.avatar} />}
                  title={<a href={item.href}>{item.title}</a>}
                  description={item.description}
                />
                {item.content}
              </Skeleton>
            </List.Item>
          )}
        />
      </div>
    );
  }
}

ReactDOM.render(<App />, mountNode);

API#

Skeleton#

PropertyDescriptionTypeDefault
activeShow animation effectbooleanfalse
avatarShow avatar placeholderboolean | SkeletonAvatarPropsfalse
loadingDisplay the skeleton when trueboolean-
paragraphShow paragraph placeholderboolean | SkeletonParagraphPropstrue
titleShow title placeholderboolean | SkeletonTitlePropstrue

SkeletonAvatarProps#

PropertyDescriptionTypeDefault
activeShow animation effect, only valid when used avatar independently.booleanfalse
sizeSet the size of avatarnumber | large | small | default }-
shapeSet the shape of avatarcircle | square-

SkeletonTitleProps#

PropertyDescriptionTypeDefault
widthSet the width of titlenumber | string-

SkeletonParagraphProps#

PropertyDescriptionTypeDefault
rowsSet the row count of paragraphnumber-
widthSet the width of paragraph. When width is an Array, it can set the width of each row. Otherwise only set the last row widthnumber | string | Array<number | string>-

SkeletonButtonProps#

PropertyDescriptionTypeDefault
activeShow animation effectbooleanfalse
sizeSet the size of buttonlarge | small | default-
shapeSet the shape of buttoncircle | round | default-

SkeletonInputProps#

PropertyDescriptionTypeDefault
activeShow animation effectbooleanfalse
sizeSet the size of buttonlarge | small | default-
SpinAnchor