diff --git a/src/cascader/README.md b/src/cascader/README.md
new file mode 100644
index 000000000..f530c2937
--- /dev/null
+++ b/src/cascader/README.md
@@ -0,0 +1,40 @@
+# Cascader
+
+### Intro
+
+### Install
+
+```js
+import Vue from 'vue';
+import { Cascader } from 'vant';
+
+Vue.use(Cascader);
+```
+
+## Usage
+
+### Basic Usage
+
+```html
+
+```
+
+## API
+
+### Props
+
+| Attribute | Description | Type | Default |
+| --------- | ----------- | ---- | ------- |
+
+
+### Events
+
+| Event | Description | Arguments |
+| ----- | ----------- | --------- |
+
+
+### Slots
+
+| Name | Description |
+| ---- | ----------- |
+
diff --git a/src/cascader/README.zh-CN.md b/src/cascader/README.zh-CN.md
new file mode 100644
index 000000000..07e2afbc7
--- /dev/null
+++ b/src/cascader/README.zh-CN.md
@@ -0,0 +1,60 @@
+# Cascader 级联选择
+
+### 介绍
+
+级联选择框,用于多层级数据的选择,典型场景为省市区选择,2.9 版本开始支持此组件。
+
+### 引入
+
+```js
+import Vue from 'vue';
+import { Cascader } from 'vant';
+
+Vue.use(Cascader);
+```
+
+## 代码演示
+
+### 基础用法
+
+```html
+
+```
+
+```js
+export default {
+ data() {
+ return {
+ show: false,
+ };
+ },
+};
+```
+
+## API
+
+### Props
+
+| 参数 | 说明 | 类型 | 默认值 |
+| ------------ | -------------------- | --------------------- | --------- |
+| show.sync | 是否显示级联选择弹窗 | _boolean_ | `false` |
+| title | 顶部标题 | _string_ | - |
+| value | 选中项的值 | `string[] | number[]` | - |
+| options | 可选项数据源 | _Option[]_ | `[]` |
+| placeholder | 未选中时的提示文案 | _string_ | `请选择` |
+| confirm-text | 确认按钮文字 | _string_ | `确认` |
+| active-color | 选中状态的高亮颜色 | _string_ | `#ee0a24` |
+
+### Events
+
+| 事件 | 说明 | 回调参数 |
+| ------- | ---------------- | -------- |
+| change | 选中项变化时触发 | - |
+| confirm | 确认选择时触发 | - |
+
+### Slots
+
+| 名称 | 说明 |
+| ------------ | -------------- |
+| title | 自定义顶部标题 |
+| confirm-text | 自定义确认按钮 |
diff --git a/src/cascader/demo/index.vue b/src/cascader/demo/index.vue
new file mode 100644
index 000000000..271fc5610
--- /dev/null
+++ b/src/cascader/demo/index.vue
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/cascader/index.js b/src/cascader/index.js
new file mode 100644
index 000000000..f5d8b93bf
--- /dev/null
+++ b/src/cascader/index.js
@@ -0,0 +1,55 @@
+import { createNamespace } from '../utils';
+import Popup from '../popup';
+
+const [createComponent, bem] = createNamespace('cascader');
+
+export default createComponent({
+ props: {
+ show: Boolean,
+ value: Array,
+ title: String,
+ options: Array,
+ placeholder: String,
+ confirmText: String,
+ activeColor: String,
+ },
+
+ methods: {
+ toggle(val) {
+ this.$emit('update:show', val);
+ },
+
+ confirm() {
+ this.toggle(false);
+ },
+
+ genHeader() {
+ const confirmText = this.confirmText || this.t('confirm');
+ return (
+
+ );
+ },
+
+ genTab() {},
+ },
+
+ render() {
+ return (
+
+ {this.genHeader()}
+ {this.genTab()}
+
+ );
+ },
+});
diff --git a/src/cascader/index.less b/src/cascader/index.less
new file mode 100644
index 000000000..d78dc4dd8
--- /dev/null
+++ b/src/cascader/index.less
@@ -0,0 +1,33 @@
+@import '../style/var';
+
+.van-cascader {
+ &__header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: @cascader-header-height;
+ padding: 0 @padding-md;
+ }
+
+ &__title {
+ font-size: @cascader-title-font-size;
+ font-weight: @font-weight-bold;
+ line-height: @cascader-title-line-height;
+ }
+
+ &__confirm {
+ height: 100%;
+ // expand click area
+ padding: 0 @padding-md;
+ margin-right: -@padding-md;
+ color: @cascader-confirm-color;
+ font-size: @cascader-confirm-font-size;
+ background-color: transparent;
+ border: none;
+ cursor: pointer;
+
+ &:active {
+ opacity: @active-opacity;
+ }
+ }
+}
diff --git a/src/cascader/test/demo.spec.js b/src/cascader/test/demo.spec.js
new file mode 100644
index 000000000..5c70922b5
--- /dev/null
+++ b/src/cascader/test/demo.spec.js
@@ -0,0 +1,4 @@
+import Demo from '../demo';
+import { snapshotDemo } from '../../../test/demo';
+
+snapshotDemo(Demo);
diff --git a/src/style/var.less b/src/style/var.less
index ad781be3a..1641457f3 100644
--- a/src/style/var.less
+++ b/src/style/var.less
@@ -201,6 +201,13 @@
@card-price-integer-font-size: @font-size-lg;
@card-price-font-family: @price-integer-font-family;
+// Cascader
+@cascader-header-height: 48px;
+@cascader-title-font-size: @font-size-lg;
+@cascader-title-line-height: 20px;
+@cascader-confirm-color: @text-link-color;
+@cascader-confirm-font-size: @font-size-md;
+
// Cell
@cell-font-size: @font-size-md;
@cell-line-height: 24px;
diff --git a/vant.config.js b/vant.config.js
index af14cccff..1206b1d92 100644
--- a/vant.config.js
+++ b/vant.config.js
@@ -142,6 +142,10 @@ module.exports = {
path: 'calendar',
title: 'Calendar 日历',
},
+ {
+ path: 'cascader',
+ title: 'Cascader 级联选择'
+ },
{
path: 'checkbox',
title: 'Checkbox 复选框',
@@ -509,6 +513,10 @@ module.exports = {
path: 'calendar',
title: 'Calendar',
},
+ {
+ path: 'cascader',
+ title: 'Cascader'
+ },
{
path: 'checkbox',
title: 'Checkbox',