+
+
+
+
+ {{ description }}
+
+
+
+
+
+
diff --git a/packages/components/tour/src/steps.ts b/packages/components/tour/src/steps.ts
new file mode 100644
index 0000000000000..114f2d9e15186
--- /dev/null
+++ b/packages/components/tour/src/steps.ts
@@ -0,0 +1,52 @@
+import { defineComponent } from 'vue'
+import { flattedChildren, isArray } from '@element-plus/utils'
+import { getNormalizedProps, isSameSteps } from './helper'
+import type { FlattenVNodes } from '@element-plus/utils'
+import type { Component, VNode } from 'vue'
+
+export default defineComponent({
+ name: 'ElTourSteps',
+ props: {
+ current: {
+ type: Number,
+ default: 0,
+ },
+ },
+ emits: ['update-steps'],
+ setup(props, { slots, emit }) {
+ let cachedSteps: any[] = []
+
+ return () => {
+ const children = slots.default?.()!
+ const filteredSteps: any[] = []
+ const result: VNode[] = []
+
+ function filterSteps(children?: FlattenVNodes) {
+ if (!isArray(children)) return
+ ;(children as VNode[]).forEach((item) => {
+ const name = ((item?.type || {}) as Component)?.name
+
+ if (name === 'ElTourStep') {
+ const booleanKeys = ['showArrow', 'mask', 'scrollIntoViewOptions']
+ filteredSteps.push(getNormalizedProps(item, booleanKeys))
+ result.push(item)
+ }
+ })
+ }
+
+ if (children.length) {
+ filterSteps(flattedChildren(children![0]?.children))
+ }
+
+ if (!isSameSteps(filteredSteps, cachedSteps)) {
+ cachedSteps = filteredSteps
+ emit('update-steps', filteredSteps)
+ }
+
+ if (result.length) {
+ return result[props.current]
+ }
+ return null
+ }
+ },
+})
diff --git a/packages/components/tour/src/tour.ts b/packages/components/tour/src/tour.ts
new file mode 100644
index 0000000000000..77e94ad6a8d3f
--- /dev/null
+++ b/packages/components/tour/src/tour.ts
@@ -0,0 +1,127 @@
+import {
+ buildProps,
+ definePropType,
+ iconPropType,
+ isBoolean,
+ isNumber,
+} from '@element-plus/utils'
+import { UPDATE_MODEL_EVENT } from '@element-plus/constants'
+import { tourContentProps } from './content'
+import type { CSSProperties, ExtractPropTypes } from 'vue'
+import type Tour from './tour.vue'
+import type { TourGap, TourMask } from './types'
+
+export const tourProps = buildProps({
+ /**
+ * @description open tour
+ */
+ modelValue: Boolean,
+ /**
+ * @description what is the current step
+ */
+ current: {
+ type: Number,
+ default: 0,
+ },
+ /**
+ * @description whether to show the arrow
+ */
+ showArrow: {
+ type: Boolean,
+ default: true,
+ },
+ /**
+ * @description whether to show a close button
+ */
+ showClose: {
+ type: Boolean,
+ default: true,
+ },
+ /**
+ * @description custom close icon
+ */
+ closeIcon: {
+ type: iconPropType,
+ },
+ /**
+ * @description position of the guide card relative to the target element
+ */
+ placement: tourContentProps.placement,
+ /**
+ * @description custom style for content
+ */
+ contentStyle: {
+ type: definePropType