diff --git a/src/empty/README.md b/src/empty/README.md
new file mode 100644
index 000000000..96b16f395
--- /dev/null
+++ b/src/empty/README.md
@@ -0,0 +1,80 @@
+# Empty
+
+### Install
+
+```js
+import Vue from 'vue';
+import { Empty } from 'vant';
+
+Vue.use(Empty);
+```
+
+## Usage
+
+### Basic Usage
+
+```html
+
+```
+
+### Image Type
+
+Use the image prop to display different placeholder images
+
+```html
+
+
+
+
+
+
+```
+
+### Custom Image
+
+```html
+
+
+
+```
+
+### Bottom Content
+
+```html
+
+
+ Button
+
+
+
+
+```
+
+## API
+
+### Props
+
+| Attribute | Description | Type | Default |
+|------|------|------|------|
+| image | Image type,can be set to `error` `network` `search` or image URL | *string* | `default` |
+| description | Desciption | *string* | - |
+
+### Slots
+
+| Name | Description |
+|------|------|
+| default | Custom bottom content |
+| image | Custom image |
+| description | Custom description |
diff --git a/src/empty/README.zh-CN.md b/src/empty/README.zh-CN.md
new file mode 100644
index 000000000..188e0740e
--- /dev/null
+++ b/src/empty/README.zh-CN.md
@@ -0,0 +1,89 @@
+# Empty 空状态
+
+### 介绍
+
+空状态时的占位提示,2.6 版本开始支持此组件
+
+### 引入
+
+```js
+import Vue from 'vue';
+import { Empty } from 'vant';
+
+Vue.use(Empty);
+```
+
+## 代码演示
+
+### 基本用法
+
+```html
+
+```
+
+### 图片类型
+
+Empty 组件内置了多种占位图片类型,可以在不同业务场景下使用
+
+```html
+
+
+
+
+
+
+```
+
+### 自定义图片
+
+需要自定义图片时,可以在 image 属性中传入任意图片 URL
+
+```html
+
+
+
+```
+
+### 底部内容
+
+通过默认插槽可以在 Empty 组件的下方插入内容
+
+```html
+
+
+ 按钮
+
+
+
+
+```
+
+## API
+
+### Props
+
+| 参数 | 说明 | 类型 | 默认值 |
+|------|------|------|------|
+| image | 图片类型,可选值为 `error` `network` `search`,支持传入图片 URL | *string* | `default` |
+| description | 图片下方的描述文字 | *string* | - |
+
+### Slots
+
+| 名称 | 说明 |
+|------|------|
+| default | 自定义底部内容 |
+| image | 自定义图标 |
+| description | 自定义描述文字 |
diff --git a/src/empty/demo/index.vue b/src/empty/demo/index.vue
new file mode 100644
index 000000000..b712d4b96
--- /dev/null
+++ b/src/empty/demo/index.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('button') }}
+
+
+
+
+
+
+
+
+
diff --git a/src/empty/index.js b/src/empty/index.js
new file mode 100644
index 000000000..8300e09cd
--- /dev/null
+++ b/src/empty/index.js
@@ -0,0 +1,58 @@
+import { createNamespace } from '../utils';
+
+const [createComponent, bem] = createNamespace('empty');
+
+const PRESETS = ['error', 'search', 'default', 'network'];
+
+export default createComponent({
+ props: {
+ description: String,
+ image: {
+ type: String,
+ default: 'default',
+ },
+ },
+
+ computed: {
+ url() {
+ if (PRESETS.indexOf(this.image) !== -1) {
+ return `https://img.yzcdn.cn/vant/empty-image-${this.image}.png`;
+ }
+
+ return this.image;
+ },
+ },
+
+ methods: {
+ genImage() {
+ const image = this.slots('image') ||
;
+ return
{image}
;
+ },
+
+ genDescription() {
+ const description = this.slots('description') || this.description;
+
+ if (description) {
+ return {description}
;
+ }
+ },
+
+ genBottom() {
+ const slot = this.slots();
+
+ if (slot) {
+ return {slot}
;
+ }
+ },
+ },
+
+ render() {
+ return (
+
+ {this.genImage()}
+ {this.genDescription()}
+ {this.genBottom()}
+
+ );
+ },
+});
diff --git a/src/empty/index.less b/src/empty/index.less
new file mode 100644
index 000000000..2a28d2b86
--- /dev/null
+++ b/src/empty/index.less
@@ -0,0 +1,32 @@
+@import '../style/var';
+
+.van-empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ padding: @empty-padding;
+
+ &__image {
+ width: @empty-image-size;
+ height: @empty-image-size;
+
+ img {
+ width: 100%;
+ height: 100%;
+ }
+ }
+
+ &__description {
+ margin-top: @empty-description-margin-top;
+ padding: @empty-description-padding;
+ color: @empty-description-color;
+ font-size: @empty-description-font-size;
+ line-height: @empty-description-line-height;
+ }
+
+ &__bottom {
+ margin-top: @empty-bottom-margin-top;
+ }
+}
diff --git a/src/empty/test/__snapshots__/demo.spec.js.snap b/src/empty/test/__snapshots__/demo.spec.js.snap
new file mode 100644
index 000000000..3771c5aba
--- /dev/null
+++ b/src/empty/test/__snapshots__/demo.spec.js.snap
@@ -0,0 +1,53 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders demo correctly 1`] = `
+
+`;
diff --git a/src/empty/test/__snapshots__/index.spec.js.snap b/src/empty/test/__snapshots__/index.spec.js.snap
new file mode 100644
index 000000000..3f2244c96
--- /dev/null
+++ b/src/empty/test/__snapshots__/index.spec.js.snap
@@ -0,0 +1,14 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`description slot 1`] = `
+
+`;
+
+exports[`image slot 1`] = `
+
+`;
diff --git a/src/empty/test/demo.spec.js b/src/empty/test/demo.spec.js
new file mode 100644
index 000000000..5c70922b5
--- /dev/null
+++ b/src/empty/test/demo.spec.js
@@ -0,0 +1,4 @@
+import Demo from '../demo';
+import { snapshotDemo } from '../../../test/demo';
+
+snapshotDemo(Demo);
diff --git a/src/empty/test/index.spec.js b/src/empty/test/index.spec.js
new file mode 100644
index 000000000..7dd7cb4ff
--- /dev/null
+++ b/src/empty/test/index.spec.js
@@ -0,0 +1,22 @@
+import Empty from '..';
+import { mount } from '../../../test';
+
+test('image slot', () => {
+ const wrapper = mount(Empty, {
+ scopedSlots: {
+ image: () => 'Custom Image',
+ },
+ });
+
+ expect(wrapper).toMatchSnapshot();
+});
+
+test('description slot', () => {
+ const wrapper = mount(Empty, {
+ scopedSlots: {
+ description: () => 'Custom description',
+ },
+ });
+
+ expect(wrapper).toMatchSnapshot();
+});
diff --git a/src/style/var.less b/src/style/var.less
index ada8b4c0e..13810ad62 100644
--- a/src/style/var.less
+++ b/src/style/var.less
@@ -333,6 +333,16 @@
@dropdown-menu-content-max-height: 80%;
@dropdown-item-z-index: 10;
+// Empty
+@empty-padding: @padding-xl 0;
+@empty-image-size: 160px;
+@empty-description-margin-top: @padding-md;
+@empty-description-padding: 0 60px;
+@empty-description-color: @gray-6;
+@empty-description-font-size: 14px;
+@empty-description-line-height: 20px;
+@empty-bottom-margin-top: 24px;
+
// Field
@field-label-width: 90px;
@field-input-text-color: @text-color;
diff --git a/types/index.d.ts b/types/index.d.ts
index 96db95695..447df1a91 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -45,6 +45,7 @@ export class CouponCell extends VanComponent {}
export class CouponList extends VanComponent {}
export class Divider extends VanComponent {}
export class DropdownMenu extends VanComponent {}
+export class Empty extends VanComponent {}
export class Grid extends VanComponent {}
export class GridItem extends VanComponent {}
export class GoodsAction extends VanComponent {}
diff --git a/vant.config.js b/vant.config.js
index bb0c6cbc3..598f28c55 100644
--- a/vant.config.js
+++ b/vant.config.js
@@ -232,6 +232,10 @@ module.exports = {
path: 'divider',
title: 'Divider 分割线',
},
+ {
+ path: 'empty',
+ title: 'Empty 空状态',
+ },
{
path: 'image-preview',
title: 'ImagePreview 图片预览',
@@ -575,6 +579,10 @@ module.exports = {
path: 'divider',
title: 'Divider',
},
+ {
+ path: 'empty',
+ title: 'Empty',
+ },
{
path: 'image-preview',
title: 'ImagePreview',