Show · UserGuide

UserGuide

Used to guide new users through pages

Demos

How to import

<script setup lang="ts">
    import { UserGuide } from '@fibrous/semi-ui-vue';
</script>

Basic Usage



Default Tag
Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, Space, Switch, Tag, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const steps: UserGuideStepItem[] = [
        {
            target: () => document.querySelector('#basic-demo-1'),
            title: '新手引导',
            description: 'Hello ByteDancer!',
            position: 'bottom',
        },
        {
            target: () => document.querySelector('#basic-demo-2'),
            title: 'Switch',
            description: 'This is a Semi Switch',
            position: 'bottom',
        },
        {
            target: () => document.querySelector('#basic-demo-3'),
            title: 'Button',
            description: 'This is a Semi Button',
            position: 'bottom',
        },
    ];
</script>

<template>
    <div>
        <Button @click="visible = true">开始引导</Button>
        <br />
        <br />
        <Space>
            <Switch id="basic-demo-1" aria-label="示例开关" defaultChecked />
            <Tag id="basic-demo-2"> Default Tag </Tag>
            <Button id="basic-demo-3">确定</Button>
        </Space>
        <UserGuide v-model:visible="visible" mask mode="popup" :steps="steps" @change="(current) => console.log('当前引导步骤', current)" @finish="console.log('引导完成')" @next="console.log('下一步引导')" @prev="console.log('上一步引导')" @skip="console.log('跳过引导')" />
    </div>
</template>

Theme

popup bubble card mode provides two themes default and primary, set by the theme property.



Default Tag
Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, Space, Switch, Tag, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const steps: UserGuideStepItem[] = [
        {
            target: () => document.querySelector('#theme-demo-1'),
            title: '新手引导',
            description: 'Hello ByteDancer!',
            position: 'bottom',
        },
        {
            target: () => document.querySelector('#theme-demo-2'),
            title: 'Switch',
            description: 'This is a Semi Switch',
            position: 'bottom',
        },
        {
            target: () => document.querySelector('#theme-demo-3'),
            title: 'Button',
            description: 'This is a Semi Button',
            position: 'bottom',
        },
    ];
</script>

<template>
    <div>
        <Button @click="visible = true">开始引导</Button>
        <br />
        <br />
        <Space>
            <Switch id="theme-demo-1" aria-label="示例开关" defaultChecked />
            <Tag id="theme-demo-2"> Default Tag </Tag>
            <Button id="theme-demo-3">确定</Button>
        </Space>
        <UserGuide v-model:visible="visible" mask mode="popup" :steps="steps" theme="primary" @finish="console.log('引导完成')" @skip="console.log('跳过引导')" />
    </div>
</template>

popup bubble card mode provides 16 positions, optional values are top, topLeft, topRight, left, leftTop, leftBottom, right, rightTop, rightBottom, bottom, bottomLeft, bottomRight, leftTopOver, rightTopOver, leftBottomOver, rightBottomOver, and can be set by the showArrow property to display the arrow.

Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const target = () => document.querySelector('#position-demo');
    const steps: UserGuideStepItem[] = [
        { target, title: '新手引导', description: 'Hello ByteDancer!', position: 'top' },
        { target, title: 'New Position', description: 'This is Right Position', position: 'right' },
        { target, title: 'Hide Arrow', description: 'We hide the arrow', position: 'bottom', showArrow: false },
    ];
</script>

<template>
    <div>
        <Button id="position-demo" @click="visible = true">开始引导</Button>
        <UserGuide v-model:visible="visible" mask mode="popup" :steps="steps" @finish="console.log('引导完成')" @skip="console.log('跳过引导')" />
    </div>
</template>

Set the size of the highlight area

Set by the spotlightPadding property.



Default Tag
Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, Space, Switch, Tag, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const steps: UserGuideStepItem[] = [
        {
            target: () => document.querySelector('#padding-demo-1'),
            title: '新手引导',
            description: 'Hello ByteDancer!',
        },
        {
            target: () => document.querySelector('#padding-demo-2'),
            title: 'New Padding',
            description: 'This is 10px padding',
        },
        {
            target: () => document.querySelector('#padding-demo-3'),
            title: 'Change Padding',
            spotlightPadding: 15,
            description: 'We change the Padding to 15px',
        },
    ];
</script>

<template>
    <div>
        <Button @click="visible = true">开始引导</Button>
        <br />
        <br />
        <Space>
            <Switch id="padding-demo-1" aria-label="示例开关" defaultChecked />
            <Tag id="padding-demo-2"> Default Tag </Tag>
            <Button id="padding-demo-3">确定</Button>
        </Space>
        <UserGuide v-model:visible="visible" mask mode="popup" :spotlightPadding="10" :steps="steps" @finish="console.log('引导完成')" @skip="console.log('跳过引导')" />
    </div>
</template>

Customize the button

Set by the nextButtonProps and prevButtonProps properties.

Use the nextText and prevText slots for the button text. The text of the button on the last step is set by finishText.



Default Tag
Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, Space, Switch, Tag, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const steps: UserGuideStepItem[] = [
        {
            target: () => document.querySelector('#button-demo-1'),
            title: '新手引导',
            description: 'Hello ByteDancer!',
        },
        {
            target: () => document.querySelector('#button-demo-2'),
            title: 'New Button Style',
            description: 'Button text is Next',
        },
        {
            target: () => document.querySelector('#button-demo-3'),
            title: 'New finish button text',
            description: 'Button text is I know',
        },
    ];
</script>

<template>
    <div>
        <Button @click="visible = true">开始引导</Button>
        <br />
        <br />
        <Space>
            <Switch id="button-demo-1" aria-label="示例开关" defaultChecked />
            <Tag id="button-demo-2"> Default Tag </Tag>
            <Button id="button-demo-3">确定</Button>
        </Space>
        <UserGuide v-model:visible="visible" finishText="我知道啦!" mask mode="popup" :prevButtonProps="{ theme: 'borderless' }" :steps="steps" @finish="console.log('引导完成')" @skip="console.log('跳过引导')">
            <template #nextText>Next</template>
            <template #prevText>Prev</template>
        </UserGuide>
    </div>
</template>

Controlled

Set by the current property.

Bind the current step with v-model:current and the visibility with v-model:visible.



Default Tag
Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, Space, Switch, Tag, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const current = ref(0);
    const steps: UserGuideStepItem[] = [
        {
            target: () => document.querySelector('#controlled-demo-1'),
            title: '新手引导',
            description: 'Hello ByteDancer!',
            position: 'bottom',
        },
        {
            target: () => document.querySelector('#controlled-demo-2'),
            title: 'Switch',
            description: 'This is a Semi Switch',
            position: 'bottom',
        },
        {
            target: () => document.querySelector('#controlled-demo-3'),
            title: 'Button',
            description: 'This is a Semi Button',
            position: 'bottom',
        },
    ];

    const finish = (message: string) => {
        current.value = 0;
        console.log(message);
    };
</script>

<template>
    <div>
        <Button @click="visible = true">开始引导</Button>
        <br />
        <br />
        <Space>
            <Switch id="controlled-demo-1" aria-label="示例开关" defaultChecked />
            <Tag id="controlled-demo-2"> Default Tag </Tag>
            <Button id="controlled-demo-3">确定</Button>
        </Space>
        <UserGuide v-model:current="current" v-model:visible="visible" mask mode="popup" :steps="steps" @finish="finish('引导完成')" @skip="finish('跳过引导')" />
    </div>
</template>

Set by the mode property.

Use the cover slot for the cover and the description slot for rich-text descriptions.

Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, Image, TypographyText, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const steps: UserGuideStepItem[] = [
        { title: '欢迎使用 Semi DSM!', position: 'bottom' },
        {
            title: '高可用的色盘',
            description: '选取主色后,我们的颜色算法会为你生成一套高可用的色盘',
            position: 'bottom',
        },
        { title: '自由定制', description: '开始定制属于你的设计系统吧!', position: 'bottom' },
    ];
    const covers = ['/assets/root-web-sites/sky.jpg', '/assets/root-web-sites/greenleaf.jpg', '/assets/root-web-sites/colorful.jpg'];
</script>

<template>
    <div>
        <Button @click="visible = true">开始引导</Button>
        <UserGuide v-model:visible="visible" mask mode="modal" :steps="steps" @change="(current) => console.log('当前引导步骤', current)" @finish="console.log('引导完成')" @next="console.log('下一步引导')" @prev="console.log('上一步引导')" @skip="console.log('跳过引导')">
            <template #description="{ index }">
                <div v-if="index === 0">你可以从已发布的主题出发,或者选择<TypographyText strong>立即创造</TypographyText>来创造一个新的主题</div>
            </template>
            <template #cover="{ index }">
                <Image height="100%" :src="covers[index]" width="600px" />
            </template>
        </UserGuide>
    </div>
</template>

No mask

Set by the mask property.

Code
<script setup lang="ts">
    import { ref } from 'vue';
    import { Button, UserGuide, type UserGuideStepItem } from '@fibrous/semi-ui-vue';

    const visible = ref(false);
    const steps: UserGuideStepItem[] = [
        {
            target: () => document.querySelector('#mask-demo'),
            title: 'No Mask',
            description: 'Hello ByteDancer!',
        },
    ];
</script>

<template>
    <div>
        <Button id="mask-demo" @click="visible = true">开始引导</Button>
        <UserGuide v-model:visible="visible" :mask="false" mode="popup" :steps="steps" @finish="console.log('引导完成')" @skip="console.log('跳过引导')" />
    </div>
</template>

API Reference


Props

PropertyDescriptionTypeDefault
currentIndex of the current step, for v-model:current. Without it the component keeps the index itself, starting at 0.numbersemiGlobalDefault("UserGuide", "current")
finishTextText of the finish button on the last step. When empty, the text from the locale pack is used.stringsemiGlobalDefault("UserGuide", "finishText")
getPopupContainerIn modal mode the dialog is rendered into this DOM node. In popup mode body scrolling is not locked when it points to an element other than body. The popover card sits in the top layer and is not affected.Type(() => HTMLElement)undefined
maskWhether to show the mask. A step's own mask overrides it.booleansemiDefault("UserGuide", "mask", true)
modeGuide mode: popup for a bubble card, modal for a dialog."popup" | "modal"semiDefault("UserGuide", "mode", "popup")
nextButtonPropsProps of the next button, which may include class, style and onClick. onClick is called before the built-in handling; use the nextText slot for the button text.UserGuideButtonPropssemiGlobalDefault("UserGuide", "nextButtonProps")
positionPosition of the bubble card relative to the target element. A step's own position overrides it.Type"top" | "bottom" | "left" | "right" | "topLeft" | "topRight" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom" | "bottomLeft" | "bottomRight" | "leftTopOver" | "rightTopOver" | "leftBottomOver" | "rightBottomOver"semiDefault("UserGuide", "position", "bottom")
prevButtonPropsProps of the previous button, which may include class, style and onClick. onClick is called before the built-in handling; use the prevText slot for the button text.UserGuideButtonPropssemiGlobalDefault("UserGuide", "prevButtonProps")
showPrevButtonWhether to show the previous button. It is never shown on the first step.booleansemiDefault("UserGuide", "showPrevButton", true)
showSkipButtonWhether to show the skip button. It is never shown on the last step.booleansemiDefault("UserGuide", "showSkipButton", true)
spotlightPaddingExtra space in pixels around the highlighted area. A step's own spotlightPadding overrides it; 5 when neither is set.numbersemiGlobalDefault("UserGuide", "spotlightPadding")
stepsData of the guide steps. Use the title, description and cover slots for custom content.UserGuideStepItem[]semiDefault("UserGuide", "steps", [])
themeTheme of the popup mode. A step's own theme overrides it."default" | "primary"semiDefault("UserGuide", "theme", "default")
visibleWhether the guide is shown, for v-model:visible.booleansemiDefault("UserGuide", "visible", false)
zIndexThe z-index of the mask in popup mode and of the dialog in modal mode. The popover card sits in the top layer, always above the mask.numbersemiDefault("UserGuide", "zIndex", numbers.DEFAULT_Z_INDEX)

Events

EventDescriptionCallback parameters
update:currentEmitted with the new index when the step changes, for v-model:current to write back. It comes before change.[current: number]
update:visibleEmitted with false when the guide is skipped, Escape is pressed or the guide is finished, for v-model:visible to write back. It comes before skip and finish.[visible: false]
changeEmitted with the new index when the step changes.[current: number]
nextEmitted with the new index when the next button is clicked. The last step emits finish instead.[current: number]
prevEmitted with the new index when the previous button is clicked.[current: number]
skipEmitted when the skip button is clicked or Escape is pressed.[]
finishEmitted when the finish button on the last step is clicked.[]

Slots

SlotDescriptionScope parameters
titleStep title, with scope { item, index }. When it renders nothing, item.title is used.UserGuideStepSlotProps
descriptionStep description, with scope { item, index }. When it renders nothing, item.description is used.UserGuideStepSlotProps
coverStep cover, with scope { item, index }. Without it the step has no cover area.UserGuideStepSlotProps
nextTextText of the next button; the last step shows finishText. Without it the text from the locale pack is used.any
prevTextText of the previous button. Without it the text from the locale pack is used.any

Exposes

NameDescriptionType
None

UserGuide has no root element. In popup mode class and style land on the popover card; in modal mode they follow Modal, with class on the outermost element inside the portal and style on .semi-modal. Other undeclared attributes such as aria-* are dropped. The dialog's accessible name comes only from the title of the current step (the title slot or item.title).

StepItem

Each item of steps (type UserGuideStepItem) holds data only. Custom content goes through the title, description and cover slots, rendered with { item, index }.

PropertiesInstructionsTypeDefault
classCustom class name of the stepstring | object | array-
targetThe target element, the highlight area will focus on this element. The function form is called when the step is measured and may return null or undefined while the target is absentElement | (() => Element | null | undefined)-
titleText of the step title; the title slot wins when it renders contentstring-
descriptionText of the step description; the description slot wins when it renders contentstring-
maskWhether to display the mask of this step, it will override the global configurationboolean-
showArrowWhether to display the arrow (only valid when mode=popup)booleantrue
spotlightPaddingThe inner padding of the highlight area of this step, it will override the global configurationnumber-
themeThe theme of this step, it will override the global configurationdefault | primary-
positionThe position of the pop-up layer of this step, it will override the global configurationPosition-

Accessibility

  • Each step is a dialog named by the step title; Escape works like clicking Skip.
  • In both modes, focus moves to the primary button (Next or Finish) when each step appears. In popup mode Tab cycles inside the card, and focus returns to the element focused before the guide when it closes; in modal mode, Modal manages the focus cycle and its return.

Design Tokens

These are the component's internal Sass variables and cannot be overridden. To customize styles, override the --semi-* CSS variables (see the Design Token page) or write unlayered CSS rules.
Sass variableValueUsage
$transition_duration-userGuide_spotLight200msspotLight 动画持续时间
$transition_function-userGuide_spotLightcubic-bezier(0.4, 0, 0.2, 1)spotLight 过渡曲线
$color-userGuide_popup-text-defaultvar(--semi-color-text-0)气泡卡片文字颜色 - 默认
$color-userGuide_popup-text-primaryvar(--semi-color-tertiary-light-default)气泡卡片文字颜色 - primary
$color-userGuide_modal_content_indicator-bgvar(--semi-color-primary-light-active)弹窗指示器背景颜色
$color-userGuide_modal_content_indicator-bg-activevar(--semi-color-primary)弹窗指示器背景颜色 - 选中态
$width-userGuide_popover-default400px默认气泡卡片宽度
$height-userGuide_popup_content_cover-default200px默认气泡卡片封面高度
$width-userGuide_modal_content_cover-default600px默认弹窗式卡片封面宽度
$height-userGuide_modal_content_cover-default300px默认弹窗式卡片封面高度
$height-userGuide_modal_content_indicator-default30px默认弹窗式卡片指示器整体高度
$width-userGuide_modal_content_indicator_item-default6px默认弹窗式卡片单个指示器宽度
$height-userGuide_modal_content_indicator_item-default6px默认弹窗式卡片单个指示器高度
$font-userGuide_popup_content_title-lineHeight24px气泡卡片标题行高
$font-userGuide_popup_content_description-lineHeight20px气泡卡片详情行高
$font-userGuide_popup_content_indicator-lineHeight20px气泡卡片指示器行高
$font-userGuide_modal_content_title-lineHeight24px弹窗式卡片标题行高
$font-userGuide_modal_content_description-lineHeight20px弹窗式卡片详情行高
$spacing-userGuide_popup_content_body-padding24px气泡卡片内边距
$spacing-userGuide_popup_content_title-marginBottom8px气泡卡片标题底部外边距
$spacing-userGuide_popup_content_description-marginBottom48px气泡卡片详情底部外边距
$spacing-userGuide_popup_content_button-gap12px气泡卡片底部按钮间距
$spacing-userGuide_popup_content_button-marginLeft120px气泡卡片按钮组左边距
$spacing-userGuide_modal_content_title-marginBottom8px弹窗式卡片标题底部外边距
$spacing-userGuide_modal_content_body-padding24px 48px弹窗式卡片body内边距
$spacing-userGuide_modal_content_footer-padding24px弹窗式卡片footer内边距
$spacing-userGuide_popup_content_indicator-gap8px弹窗式片指示器间距
$spacing-userGuide_modal_content_button-gap12px弹窗式卡片底部按钮间距
$radius-userGuide_popup_content_covervar(--semi-border-radius-medium) var(--semi-border-radius-medium) 0 0气泡卡片封面圆角
$radius-userGuide_modal_content_indicatorvar(--semi-border-radius-large)气泡卡片指示器圆角
$font-userGuide_popup_content_title-fontSize$font-size-header-5气泡卡片标题字体大小
$font-userGuide_popup_content_description-fontSize$font-size-regular气泡卡片详情字体大小
$font-userGuide_popup_content_title-fontWeight$font-weight-bold气泡卡片标题字重
$font-userGuide_modal_content_title-fontSize$font-size-header-5弹窗式卡片标题字体大小
$font-userGuide_modal_content_description-fontSize$font-size-regular弹窗式卡详情字体大小
$font-userGuide_modal_content_title-fontWeight$font-weight-bold弹窗式卡片标题字重