diff --git a/components/collapse/Collapse.vue b/components/collapse/Collapse.vue
new file mode 100644
index 000000000..a1f39fbc4
--- /dev/null
+++ b/components/collapse/Collapse.vue
@@ -0,0 +1,42 @@
+
diff --git a/components/collapse/CollapsePanel.vue b/components/collapse/CollapsePanel.vue
new file mode 100644
index 000000000..d3edde855
--- /dev/null
+++ b/components/collapse/CollapsePanel.vue
@@ -0,0 +1,27 @@
+
diff --git a/components/collapse/demo/accordion.md b/components/collapse/demo/accordion.md
new file mode 100644
index 000000000..90e2f6ca9
--- /dev/null
+++ b/components/collapse/demo/accordion.md
@@ -0,0 +1,36 @@
+
+#### 手风琴
+手风琴,每次只打开一个tab。默认打开第一个。
+
+
+
+#### Accordion
+Accordion mode, only one panel can be expanded at a time. The first panel will be expanded by default.
+
+
+```html
+
+
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+
+
+
+```
diff --git a/components/collapse/demo/basic.md b/components/collapse/demo/basic.md
new file mode 100644
index 000000000..6d3037988
--- /dev/null
+++ b/components/collapse/demo/basic.md
@@ -0,0 +1,42 @@
+
+#### 折叠面板
+可以同时展开多个面板,这个例子默认展开了第一个。
+
+
+
+#### Collapse
+More than one panel can be expanded at a time, the first panel is initialized to be active in this case.
+
+
+```html
+
+
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+
+
+
+```
diff --git a/components/collapse/demo/borderless.md b/components/collapse/demo/borderless.md
new file mode 100644
index 000000000..80ded4270
--- /dev/null
+++ b/components/collapse/demo/borderless.md
@@ -0,0 +1,36 @@
+
+#### 简洁风格
+一套没有边框的简洁样式。
+
+
+
+#### Borderless
+A borderless style of Collapse.
+
+
+```html
+
+
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+
+
+
+```
diff --git a/components/collapse/demo/custom.md b/components/collapse/demo/custom.md
new file mode 100644
index 000000000..ae19e02d2
--- /dev/null
+++ b/components/collapse/demo/custom.md
@@ -0,0 +1,37 @@
+
+#### 自定义面板
+自定义各个面板的背景色、圆角和边距。
+
+
+
+#### Custom Panel
+Customize the background, border and margin styles for each panel.
+
+
+```html
+
+
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+
+
+
+```
diff --git a/components/collapse/demo/index.vue b/components/collapse/demo/index.vue
new file mode 100644
index 000000000..37ca57d19
--- /dev/null
+++ b/components/collapse/demo/index.vue
@@ -0,0 +1,53 @@
+
diff --git a/components/collapse/demo/mix.md b/components/collapse/demo/mix.md
new file mode 100644
index 000000000..bd7a3fdc1
--- /dev/null
+++ b/components/collapse/demo/mix.md
@@ -0,0 +1,45 @@
+
+#### 面板嵌套
+嵌套折叠面板。
+
+
+
+#### Nested panel
+`Collapse` is nested inside the `Collapse`.
+
+
+```html
+
+
+
+
+
+
+ {{text}}
+
+
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+
+
+
+```
diff --git a/components/collapse/demo/noarrow.md b/components/collapse/demo/noarrow.md
new file mode 100644
index 000000000..eb9a805d9
--- /dev/null
+++ b/components/collapse/demo/noarrow.md
@@ -0,0 +1,38 @@
+
+#### 隐藏箭头
+你可以通过 `:showArrow="false"` 隐藏 `a-collapse-panel` 组件的箭头图标。
+
+
+
+#### No arrow
+You can disable showing arrow icon by passing `:showArrow="false"` to `a-collapse-panel` component.
+
+
+```html
+
+
+
+
+ {{text}}
+
+
+ {{text}}
+
+
+
+
+
+```
diff --git a/components/collapse/index.en-US.md b/components/collapse/index.en-US.md
new file mode 100644
index 000000000..6053afb58
--- /dev/null
+++ b/components/collapse/index.en-US.md
@@ -0,0 +1,18 @@
+## API
+
+### Collapse
+
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| value | name of the active panel | \[]\|string | No default value. In `accordion` mode, it's the name of the first panel. |
+| defaultValue | name of the initial active panel | string | - |
+| change | Callback function executed when active panel is changed | Function | - |
+
+### Collapse.Panel
+
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| disabled | If `true`, panel cannot be opened or closed | boolean | `false` |
+| header | Title of the panel | string | - |
+| name | Unique name identifying the panel from among its siblings | string | - |
+| showArrow | If `false`, panel will not show arrow icon | boolean | `true` |
diff --git a/components/collapse/index.js b/components/collapse/index.js
new file mode 100644
index 000000000..db3809adc
--- /dev/null
+++ b/components/collapse/index.js
@@ -0,0 +1,5 @@
+import Collapse from './Collapse'
+import CollapsePanel from './CollapsePanel'
+
+Collapse.Panel = CollapsePanel
+export default Collapse
diff --git a/components/collapse/index.zh-CN.md b/components/collapse/index.zh-CN.md
new file mode 100644
index 000000000..9a2715c59
--- /dev/null
+++ b/components/collapse/index.zh-CN.md
@@ -0,0 +1,17 @@
+## API
+
+### Collapse
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| value | 当前激活 tab 面板的 name | []\|string | 默认无,accordion模式下默认第一个元素 |
+| defaultValue | 初始化选中面板的 name | string | 无 |
+| change | 切换面板的回调 | Function | 无 |
+
+### Collapse.Panel
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| disabled | 禁用后的面板展开与否将无法通过用户交互改变 | boolean | false |
+| header | 面板头内容 | string | 无 |
+| name | 对应 activeKey | string | 无 |
diff --git a/components/collapse/src/Collapse.vue b/components/collapse/src/Collapse.vue
new file mode 100644
index 000000000..fa2cf050e
--- /dev/null
+++ b/components/collapse/src/Collapse.vue
@@ -0,0 +1,123 @@
+
diff --git a/components/collapse/src/Panel.vue b/components/collapse/src/Panel.vue
new file mode 100644
index 000000000..b2e1be2d0
--- /dev/null
+++ b/components/collapse/src/Panel.vue
@@ -0,0 +1,69 @@
+
diff --git a/components/collapse/src/PanelContent.vue b/components/collapse/src/PanelContent.vue
new file mode 100644
index 000000000..36c13bb14
--- /dev/null
+++ b/components/collapse/src/PanelContent.vue
@@ -0,0 +1,32 @@
+
diff --git a/components/collapse/src/commonProps.js b/components/collapse/src/commonProps.js
new file mode 100644
index 000000000..a4cb6d14a
--- /dev/null
+++ b/components/collapse/src/commonProps.js
@@ -0,0 +1,32 @@
+import PropTypes from '../../_util/vue-types'
+
+const collapseProps = {
+ prefixCls: PropTypes.string,
+ value: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.arrayOf(PropTypes.string),
+ ]),
+ defaultValue: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.arrayOf(PropTypes.string),
+ ]),
+ accordion: PropTypes.bool.def(false),
+ destroyInactivePanel: PropTypes.bool.def(false),
+}
+
+const panelProps = {
+ openAnimation: PropTypes.object,
+ prefixCls: PropTypes.string,
+ header: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
+ PropTypes.node,
+ ]),
+ headerClass: PropTypes.string.def(''),
+ showArrow: PropTypes.bool.def(true),
+ isActive: PropTypes.bool.def(false),
+ destroyInactivePanel: PropTypes.bool.def(false),
+ disabled: PropTypes.bool.def(false),
+}
+
+export { collapseProps, panelProps }
diff --git a/components/collapse/src/index.js b/components/collapse/src/index.js
new file mode 100644
index 000000000..ce0739f3c
--- /dev/null
+++ b/components/collapse/src/index.js
@@ -0,0 +1,6 @@
+import CollapsePanel from './Panel'
+import Collapse from './Collapse'
+
+Collapse.Panel = CollapsePanel
+
+export default Collapse
diff --git a/components/collapse/src/openAnimationFactory.js b/components/collapse/src/openAnimationFactory.js
new file mode 100644
index 000000000..c8cc8b41a
--- /dev/null
+++ b/components/collapse/src/openAnimationFactory.js
@@ -0,0 +1,35 @@
+import cssAnimation from 'css-animation'
+
+function animate (node, show, transitionName, done) {
+ let height
+ return cssAnimation(node, transitionName, {
+ start () {
+ if (!show) {
+ node.style.height = `${node.offsetHeight}px`
+ } else {
+ height = node.offsetHeight
+ node.style.height = 0
+ }
+ },
+ active () {
+ node.style.height = `${show ? height : 0}px`
+ },
+ end () {
+ node.style.height = ''
+ done()
+ },
+ })
+}
+
+function animation (prefixCls) {
+ return {
+ enter (node, done) {
+ return animate(node, true, `${prefixCls}-anim`, done)
+ },
+ leave (node, done) {
+ return animate(node, false, `${prefixCls}-anim`, done)
+ },
+ }
+}
+
+export default animation
diff --git a/components/collapse/style/index.js b/components/collapse/style/index.js
new file mode 100644
index 000000000..cf31ed80f
--- /dev/null
+++ b/components/collapse/style/index.js
@@ -0,0 +1,2 @@
+import '../../style/index.less'
+import './index.less'
diff --git a/components/collapse/style/index.less b/components/collapse/style/index.less
new file mode 100644
index 000000000..39e59f1d8
--- /dev/null
+++ b/components/collapse/style/index.less
@@ -0,0 +1,128 @@
+@import "../../style/themes/default";
+@import "../../style/mixins/index";
+
+@collapse-prefix-cls: ~"@{ant-prefix}-collapse";
+
+@collapse-header-bg: @background-color-light;
+@collapse-active-bg: @background-color-base;
+
+.collapse-close() {
+ transform: rotate(0);
+}
+.collapse-open() {
+ transform: rotate(90deg);
+}
+
+.@{collapse-prefix-cls} {
+ .reset-component;
+ background-color: @collapse-header-bg;
+ border-radius: @border-radius-base;
+ border: @border-width-base @border-style-base @border-color-base;
+ border-bottom: 0;
+
+ & > &-item {
+ border-bottom: @border-width-base @border-style-base @border-color-base;
+
+ &:last-child {
+ &,
+ & > .@{collapse-prefix-cls}-header {
+ border-radius: 0 0 @border-radius-base @border-radius-base;
+ }
+ }
+
+ > .@{collapse-prefix-cls}-header {
+ line-height: 22px;
+ padding: 12px 0 12px 40px;
+ color: @heading-color;
+ cursor: pointer;
+ position: relative;
+ transition: all .3s;
+
+ .arrow {
+ .iconfont-mixin();
+ .collapse-close();
+ font-size: @font-size-sm;
+ position: absolute;
+ display: inline-block;
+ line-height: 46px;
+ vertical-align: top;
+ transition: transform 0.24s;
+ top: 0;
+ left: @padding-md;
+ &:before {
+ content: "\E61F";
+ }
+ }
+ }
+
+ &.@{collapse-prefix-cls}-no-arrow {
+ > .@{collapse-prefix-cls}-header {
+ padding-left: 12px;
+ }
+ }
+ }
+
+ &-anim-active {
+ transition: height .2s @ease-out;
+ }
+
+ &-content {
+ overflow: hidden;
+ color: @text-color;
+ padding: 0 @padding-md;
+ background-color: @component-background;
+ border-top: @border-width-base @border-style-base @border-color-base;
+
+ & > &-box {
+ padding-top: @padding-md;
+ padding-bottom: @padding-md;
+ }
+
+ &-inactive {
+ display: none;
+ }
+ }
+
+ &-item:last-child {
+ > .@{collapse-prefix-cls}-content {
+ border-radius: 0 0 @border-radius-base @border-radius-base;
+ }
+ }
+
+ & > &-item > &-header[aria-expanded="true"] {
+ .arrow {
+ .collapse-open();
+ }
+ }
+
+ &-borderless {
+ background-color: @component-background;
+ border: 0;
+ }
+
+ &-borderless > &-item {
+ border-bottom: 1px solid @border-color-base;
+ }
+
+ &-borderless > &-item:last-child,
+ &-borderless > &-item:last-child &-header {
+ border-radius: 0;
+ }
+
+ &-borderless > &-item > &-content {
+ background-color: transparent;
+ border-top: 0;
+ }
+
+ &-borderless > &-item > &-content > &-content-box {
+ padding-top: 4px;
+ }
+
+ & &-item-disabled > &-header {
+ &,
+ & > .arrow {
+ cursor: not-allowed;
+ color: @disabled-color;
+ }
+ }
+}
diff --git a/components/index.js b/components/index.js
index 610185856..dbc9732f0 100644
--- a/components/index.js
+++ b/components/index.js
@@ -55,3 +55,7 @@ const DropdownButton = Dropdown.Button
export { Dropdown, DropdownButton }
export { default as Divider } from './divider'
+
+import Collapse from './collapse'
+const CollapsePanel = Collapse.Panel
+export { Collapse, CollapsePanel }
diff --git a/components/style.js b/components/style.js
index a4554cf93..ab2b465ea 100644
--- a/components/style.js
+++ b/components/style.js
@@ -16,3 +16,5 @@ import './popconfirm/style'
import './menu/style'
import './dropdown/style'
import './divider/style'
+import './card/style'
+import './collapse/style'
diff --git a/examples/demo.js b/examples/demo.js
index 8c8beddc1..874cade54 100644
--- a/examples/demo.js
+++ b/examples/demo.js
@@ -18,4 +18,5 @@ export { default as tag } from 'antd/tag/demo/index.vue'
export { default as tooltip } from 'antd/tooltip/demo/index.vue'
export { default as dropdown } from 'antd/dropdown/demo/index.vue'
export { default as divider } from 'antd/divider/demo/index.vue'
+export { default as collapse } from 'antd/collapse/demo/index.vue'
diff --git a/examples/routes.js b/examples/routes.js
index 1b61e245f..ee71d394d 100644
--- a/examples/routes.js
+++ b/examples/routes.js
@@ -1,7 +1,7 @@
import Demo from './components/demo.vue'
const AsyncComp = () => {
return {
- component: import(`../components/dropdown/demo/sub-menu.md`),
+ component: import(`../components/collapse/demo/index.vue`),
}
}
export default [