AI Component · Sidebar

Sidebar

Display configuration and detail information in AI scenarios

Usage Scenarios

The Sidebar is mainly used in AI scenarios for information display and feature configuration, including MCP configuration, reference sources, code preview, rich text preview and editing, etc.

Code Examples

How to import

<script setup lang="ts">
    import { Annotation, MCPConfigure, Sidebar } from '@fibrous/semi-ai-vue';

    const { Container, CodeContent, CodeItem, FileContent, FileItem } = Sidebar;
    const { AnnotationContent } = Annotation;
</script>

Basic Container

The basic container of the Sidebar is the base container for MCP configuration, References and Sidebar.

  • v-model:visible controls show/hide. Clicking the close button, or pressing Esc when closeOnEsc is true, updates it to false first and then emits cancel
  • title sets a plain-text title; use the #title slot for custom content
  • motion sets whether to enable the expand animation
  • resizable sets whether the width is resizable. When true, you can use minWidth and maxWidth to control min and max width
是否有动画
是否可伸缩
Code
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';
    import { Button, Switch } from '@fibrous/semi-ui-vue';

    const { Container } = Sidebar;

    const containerStyle = {
        display: 'flex',
        height: '500px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    const visible = shallowRef(true);
    const motion = shallowRef(true);
    const resizable = shallowRef(true);
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
            <div>
                <Button :aria-pressed="visible" @click="visible = !visible">显示容器</Button>
                <div :style="{ display: 'flex', alignItems: 'center', marginTop: '10px' }">
                    <span id="sidebar-container-motion">是否有动画</span>
                    <Switch v-model="motion" aria-labelledby="sidebar-container-motion" />
                </div>
                <div :style="{ display: 'flex', alignItems: 'center', marginTop: '10px' }">
                    <span id="sidebar-container-resizable">是否可伸缩</span>
                    <Switch v-model="resizable" aria-labelledby="sidebar-container-resizable" />
                </div>
            </div>
        </div>
        <Container v-model:visible="visible" maxWidth="60%" :minWidth="250" :motion="motion" :resizable="resizable" :style="resizable ? undefined : { width: '200px' }" title="基础容器示例" />
    </div>
</template>

MCP Configuration

Use MCPConfigure to display, enable/disable, configure and search MCP tools.

  • Bind v-model:options and v-model:customOptions to the built-in and custom MCP tools; switching a tool updates the bound value first and then emits statusChange
  • Use v-model:visible to control show and hide, and cancel to listen to user close behavior
  • Use statusChange to handle enabling/disabling of MCP tools
  • Use addClick to handle actions after clicking the Add button in custom MCP page
  • Use configureClick to listen to configuration of built-in MCP tools, and editClick to listen to configuration of custom MCP tools
  • Use the #icon and #desc slots for the icon and description of an item, and #item to replace the whole row; the slot parameters are { item, index, custom }

For other APIs of MCPConfigure, see MCPConfigure.

The type of MCP tool item is as follows:

interface MCPConfigureOption {
    icon?: string; // image URL; use the #icon slot for other content
    label?: string;
    value: string; // required, identifies the tool and must be unique
    desc?: string; // plain text; use the #desc slot for other content
    active?: boolean;
    disabled?: boolean;
    configure?: boolean; // whether to show configure button
}

Usage example:

MCP 配置
已激活 MCP 数: 0/2
支持 Semi 的文档、源码搜索,辅助开发
Figma MCP Server 连接Figma与AI开发工具的功能。它通过标准化的模型上下文协MCP),将组件、变量等设计数据和上下文暴露给AI,从而实现从设计稿到代码的智能生成,显著提升开发效率。
Code
<script setup lang="ts">
    import { shallowRef, useTemplateRef, type Component } from 'vue';
    import { MCPConfigure, type MCPConfigureOption } from '@fibrous/semi-ai-vue';
    import { IconFigma, IconSemiLogo } from '@fibrous/semi-icons-vue';
    import { Button, Form, FormInput, FormTextArea, Modal, type FormHandle } from '@fibrous/semi-ui-vue';

    interface McpFormValues {
        name: string;
        src: string;
        desc: string;
    }

    const containerStyle = {
        display: 'flex',
        height: '500px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    // icon only takes an image URL, so the built-in options get their icons from the #icon slot
    const builtinIcons: Record<string, Component> = {
        'Semi mcp': IconSemiLogo,
        figma: IconFigma,
    };

    const srcRules = [
        { required: true, message: '请输入 MCP 图标 URL' },
        {
            validator: (_rule: unknown, value: string) => /^(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+(?::\d+)?(?:\/[^\s]*)?$/i.test(value),
            message: '请输入有效的 MCP 图标 URL',
        },
    ];

    let index = 1;

    const visible = shallowRef(true);
    const options = shallowRef<MCPConfigureOption[]>([
        {
            value: 'Semi mcp',
            label: 'Semi',
            configure: true,
            desc: '支持 Semi 的文档、源码搜索,辅助开发',
        },
        {
            value: 'figma',
            label: 'Figma',
            desc: 'Figma MCP Server 连接Figma与AI开发工具的功能。它通过标准化的模型上下文协MCP),将组件、变量等设计数据和上下文暴露给AI,从而实现从设计稿到代码的智能生成,显著提升开发效率。',
        },
    ]);
    const customOptions = shallowRef<MCPConfigureOption[]>([]);
    const modalVisible = shallowRef(false);
    const form = useTemplateRef<FormHandle<McpFormValues>>('form');

    const handleOk = () => {
        form.value?.formApi
            .validate()
            .then((values) => {
                customOptions.value = [
                    ...customOptions.value,
                    {
                        label: values.name,
                        icon: values.src,
                        value: `mcp-${index++}`,
                        desc: values.desc,
                    },
                ];
                modalVisible.value = false;
            })
            .catch((errors) => {
                console.log('errors', errors);
            });
    };

    const onConfigureClick = (_event: MouseEvent, option: MCPConfigureOption) => {
        console.log('configure click', option);
    };

    const onEditClick = (_event: MouseEvent, option: MCPConfigureOption) => {
        console.log('edit click', option);
    };
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
            <Button :aria-pressed="visible" @click="visible = !visible">MCP 配置</Button>
        </div>
        <MCPConfigure v-model:customOptions="customOptions" v-model:options="options" v-model:visible="visible" :resizable="false" :style="{ width: '500px' }" @addClick="modalVisible = true" @configureClick="onConfigureClick" @editClick="onEditClick">
            <template #icon="{ item }">
                <img v-if="item.icon" alt="" :src="item.icon" :style="{ width: '100%', height: '100%' }" />
                <component :is="builtinIcons[item.value]" v-else />
            </template>
        </MCPConfigure>
        <Modal v-model:visible="modalVisible" closeOnEsc title="自定义 MCP" @ok="handleOk">
            <Form ref="form" layout="vertical" @valueChange="(values) => console.log(values)">
                <FormInput field="name" label="MCP 名称" :rules="[{ required: true, message: '请输入 MCP 名称' }]" :style="{ width: '100%' }" />
                <FormInput field="src" initValue="/assets/placeholder/avatar-a.svg" label="MCP 图标 URL" :rules="srcRules" :style="{ width: '100%' }" />
                <FormTextArea field="desc" label="MCP 介绍" :rules="[{ required: true, message: '请输入 MCP 介绍' }]" :style="{ width: '100%' }" />
            </Form>
        </Modal>
    </div>
</template>

References

Use the Annotation component to manage the display of reference sources.

  • Use v-model:activeKey to manage the currently expanded item
  • info sets the reference content list
  • click is emitted when a reference is clicked, with the event and the item
  • Use the #infoHeader slot for a group header and #item to replace an item; #header is the header of the whole container
Code
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Annotation, type AnnotationInfo, type AnnotationItem } from '@fibrous/semi-ai-vue';
    import { Button } from '@fibrous/semi-ui-vue';

    const containerStyle = {
        display: 'flex',
        height: '500px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    const logo = '/assets/placeholder/avatar-a.svg';
    const img = '/assets/root-web-sites/abstract.jpg';

    const defaultInfoList: AnnotationInfo[] = [
        {
            header: 'Semi design introduction',
            key: '1',
            annotations: [
                {
                    order: 1,
                    type: 'video',
                    duration: 4432,
                    title: 'Semi Design is a design system designed',
                    url: 'https://semi.design/',
                    logo,
                    siteName: 'Semi Design',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    img,
                },
                {
                    order: 2,
                    title: 'Quick start',
                    type: 'video',
                    duration: 56,
                    url: 'https://semi.design/',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
                {
                    order: 3,
                    title: 'Use components in a modular way',
                    url: 'https://semi.design/',
                    detail: `Semi provides esm format dist, and the css of the component is only imported by the corresponding js.
When used in Webpack, Rspack, create-react-app or Vite projects, there is no need to configure any compilation items.`,
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
            ],
        },
        {
            header: 'Design resource',
            key: '2',
            annotations: [
                {
                    order: 2,
                    title: 'Semi Design resource',
                    url: 'https://semi.design/',
                    detail: 'Semi Design provides a wealth of design resources to help designers and developers collaborate efficiently. Whether you are a community user or a ByteDance internal designer, you can find UI Kit resource and Figma plug-ins that suit you here.',
                    logo,
                    siteName: 'Semi Design resource',
                    img,
                },
            ],
        },
    ];

    const defaultSize = { width: 420 };
    const visible = shallowRef(true);
    const activeKey = shallowRef<string | string[]>('1');

    const onChange = (key: string | string[]) => {
        console.log('change', key);
    };

    const onClick = (event: MouseEvent, item: AnnotationItem) => {
        console.log('click', event, item);
    };
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">
            <Button :aria-pressed="visible" @click="visible = !visible">参考来源</Button>
        </div>
        <Annotation v-model:activeKey="activeKey" v-model:visible="visible" :defaultSize="defaultSize" :info="defaultInfoList" @change="onChange" @click="onClick" />
    </div>
</template>

Code Display

You can use CodeItem in Sidebar to display code. CodeItem is built based on JsonViewer and CodeHighlight.

  • content: content string
  • isJson: whether the content is json
  • language: programming language name, same as language in CodeHighlight; register it with CodeHighlight.register first
  • jsonViewerProps: configure other JsonViewer props
  • codeHighlightProps: configure other CodeHighlight props

The value of JsonViewer is called modelValue in jsonViewerProps, and both jsonViewerProps and codeHighlightProps accept class and style. The custom rendering and search button of JsonViewer are available through the #customRender and #searchButton slots of CodeItem.

Code
<script setup lang="ts">
    import { computed, shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';
    import { Radio, RadioGroup, type RadioValue } from '@fibrous/semi-ui-vue';

    const { CodeItem } = Sidebar;

    const code = `.semi-animation-react-demo-auto {
    button {
        height: 50px;
        border: 0;
        cursor: pointer !important;
        background: #777;
        color: white;
        outline: none;
        -webkit-appearance: none;
    }

    button:hover {
        background: #878787;
    }

    .auto-main {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: auto 1fr;
        background: #575757;
    }

    .content {
        grid-column: span 3;
    }

    .item {
        background: indianred;
        width: 100%;
        overflow: hidden;
        color: white;
    }

    .item p {
        margin: 0;
        padding: 10px;
    }
}
`;

    const json = `{
    "axisX": {
        "title": {
            "visible": false,
            "position": "center"
        },
        "label": {
            "visible": true,
            "style": {
                "fontSize": 12,
                "fontWeight": 400,
                "lineHeight": 16,
                "fontFamily": [
                    "Inter"
                ],
                "fill": "rgba(0, 0, 0, 0.47843137254901963)"
            },
            "space": 12
        }
    }
}`;

    const codeProps = {
        content: code,
        language: 'css',
    };

    const jsonProps = {
        isJson: true,
        content: json,
    };

    const type = shallowRef<RadioValue | undefined>('json');
    const itemProps = computed(() => (type.value === 'json' ? jsonProps : codeProps));
</script>

<template>
    <RadioGroup v-model="type" buttonSize="middle" :style="{ marginBottom: '10px' }" type="button">
        <Radio value="json">JSON</Radio>
        <Radio value="css">CSS</Radio>
    </RadioGroup>
    <div :style="{ height: '200px', overflow: 'auto' }">
        <CodeItem v-bind="itemProps" />
    </div>
</template>

Code List

You can use CodeContent in Sidebar to display a list of code blocks.

  • Use v-model:activeKey to manage the expanded panels
  • Use expand to listen to the expand button in a panel header
  • #customRender and #searchButton are forwarded to the JsonViewer of every JSON panel
import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';

() => {
    const [stringData, setStringData] = useState([]);
    const [value, setValue] = useState('');
    const handleStringSearch = (value) => {
        let result;
        if (value) {
            result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
        } else {
            result = [];
        }
        setStringData(result);
    };

    const handleChange = (value) => {
        console.log('onChange', value);
        setValue(value);
    };
    return (
        <AutoComplete
            data={stringData}
            value={value}
            showClear
            prefix={<IconSearch />}
            placeholder="搜索... "
            onSearch={handleStringSearch}
            onChange={handleChange}
            style={{ width: 200 }}
        />
    );
};
Code
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';

    const { CodeContent } = Sidebar;

    const defaultCodes = [
        {
            name: 'Component.js',
            key: 'code1',
            language: 'javascript',
            content: `import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';

() => {
    const [stringData, setStringData] = useState([]);
    const [value, setValue] = useState('');
    const handleStringSearch = (value) => {
        let result;
        if (value) {
            result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
        } else {
            result = [];
        }
        setStringData(result);
    };

    const handleChange = (value) => {
        console.log('onChange', value);
        setValue(value);
    };
    return (
        <AutoComplete
            data={stringData}
            value={value}
            showClear
            prefix={<IconSearch />}
            placeholder="搜索... "
            onSearch={handleStringSearch}
            onChange={handleChange}
            style={{ width: 200 }}
        />
    );
};
`,
        },
        {
            name: 'Style.css',
            key: 'code2',
            language: 'css',
            content: `.semi-animation-react-demo-auto {
    button {
        height: 50px;
        border: 0;
        cursor: pointer !important;
        background: #777;
        color: white;
        outline: none;
        -webkit-appearance: none;
    }

    button:hover {
        background: #878787;
    }

    .auto-main {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: auto 1fr;
        background: #575757;
    }

    .content {
        grid-column: span 3;
    }

    .item {
        background: indianred;
        width: 100%;
        overflow: hidden;
        color: white;
    }

    .item p {
        margin: 0;
        padding: 10px;
    }
}
`,
        },
        {
            name: 'Chart.json',
            key: 'code3',
            isJson: true,
            language: 'html',
            content: `{
    "axisX": {
        "title": {
            "visible": false,
            "position": "center"
        },
        "label": {
            "visible": true,
            "style": {
                "fontSize": 12,
                "fontWeight": 400,
                "lineHeight": 16,
                "fontFamily": [
                    "Inter"
                ],
                "fill": "rgba(0, 0, 0, 0.47843137254901963)"
            },
            "space": 12
        },
        "domainLine": {
            "visible": true,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(0, 0, 0, 0.12156862745098039)",
                "lineDash": []
            }
        },
        "tick": {
            "visible": false,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(255, 255, 255, 0)"
            }
        },
        "subTick": {
            "visible": false
        },
        "grid": {
            "visible": false
        },
        "subGrid": {
            "visible": false
        }
    }
}`,
        },
    ];

    const activeKey = shallowRef<string | string[]>('code1');
</script>

<template>
    <div class="semi-sidebar-main">
        <CodeContent v-model:activeKey="activeKey" :codes="defaultCodes" :style="{ width: '600px' }" />
    </div>
</template>

Rich Text Editor

You can use FileItem in Sidebar to view and edit rich text content. FileItem is implemented based on tiptap.

  • content: rich text as HTML. A change after mount is synced to the editor; it is not applied when it equals what the editor already holds, so typing and the cursor are not interrupted. The sync does not emit contentChange
  • editable: whether the content is editable; a change after mount is synced to the editor
  • imgUploadProps: configure image upload endpoint and how to set the src after upload. Use action to set upload url and getUploadImageSrc(response) to return the uploaded image url from the upload response (when omitted, a string response is used as the url, otherwise response.src), which will be used as src of img node in rich text; the on listeners of Upload (such as onSuccess) can be passed here too. The toolbar shows the image button only when action or customRequest is set
  • extensions and imgUploadProps are read only when the editor is created; change the key to remount it with new values
  • contentChange is emitted after an edit, with the content as HTML


Code
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar, type ImageUploadNodeOptions } from '@fibrous/semi-ai-vue';
    import { Button } from '@fibrous/semi-ui-vue';

    const { FileItem } = Sidebar;

    const content = `<h2>
  Semi Design 介绍
</h2>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>`;

    const imgUploadProps: ImageUploadNodeOptions = {
        action: 'https://api.semi.design/upload',
        // response is the action's result; real code reads the uploaded image URL from it
        getUploadImageSrc: () => '/assets/placeholder/avatar-a.svg',
    };

    const editable = shallowRef(true);
</script>

<template>
    <Button :aria-pressed="editable" @click="editable = !editable">可编辑</Button>
    <br />
    <br />
    <FileItem :content="content" :editable="editable" :imgUploadProps="imgUploadProps" name="Semi Design 介绍" :style="{ border: '1px solid var(--semi-color-border)', padding: '12px' }" />
</template>

Rich Text List

You can use FileContent in Sidebar to display a list of rich text documents.

  • Use v-model:activeKey to manage the expanded panels
  • Use expand to listen to the expand button in a panel header
Code
<script setup lang="ts">
    import { shallowRef } from 'vue';
    import { Sidebar } from '@fibrous/semi-ai-vue';

    const { FileContent } = Sidebar;

    const defaultFiles = [
        {
            key: 'file1',
            name: 'Semi Design 介绍',
            content: `
<h2>
  Semi Design 介绍
</h2>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
`,
        },
        {
            key: 'file2',
            name: 'Semi Design DSM',
            content: `<h2>
  Semi Design DSM
</h2>
<p>Semi DSM is a design system management tool provided by Semi Design. It supports global and component-level style customization and keeps synchronization between Figma and front-end code. Suitable for teams of all sizes. Whether you need to simplify workflow, improve team collaboration, or increase productivity, we have features suitable for you.</p>
`,
        },
        {
            key: 'file3',
            name: 'React v19 Adaptation',
            content: `<h2>
  React v19 Adaptation
</h2>
<p>Since the release of React v19, React has introduced numerous underlying mechanism and API changes, including upgrades and adjustments to the render mechanism, ref, context, TypeScript types, and related deprecated APIs. To ensure that the Semi Design component library is smoothly compatible with both React v19 and lower versions, we provide the original component package @fibrous/semi-ui-react for React versions below v19, as well as a new package @fibrous/semi-ui-19 specifically adapted for React v19, so users can choose as needed. This guide will help you understand how to install, use, and the precautions to take.
Installation & Usage
If your project is using React v19, please use @fibrous/semi-ui-19. For React versions below v19, continue using @fibrous/semi-ui-react as before.</p>
`,
        },
    ];

    const activeKey = shallowRef<string | string[]>('file1');
</script>

<template>
    <div class="semi-sidebar-main">
        <FileContent v-model:activeKey="activeKey" :files="defaultFiles" :style="{ width: '600px' }" />
    </div>
</template>

The Sidebar has a main view (mode is main) and detail views (mode is code, file and other custom values).

In the main view you can configure the title through title or the #title slot, decide whether to show close button through showClose, and configure the top button group through options (each item is { name, key }); v-model:activeKey binds the selected item. Use the #optionIcon="{ item, index }" slot for the button icon, or #optionItem to replace the whole button, whose onClick parameter selects the item.

For content rendering in the main view, use the #mainContent="{ activeKey }" slot and render by the selected item. You can use AnnotationContent in Annotation to render references, FileContent in Sidebar to render rich text, and CodeContent to render code.

For detail views, if the content is rich text or code, set mode to code or file and provide detailContent to display the content with built-in code display component / rich text editor; a new key in detailContent remounts it. If you want to customize how the detail view is rendered, use the #detailContent="{ mode }" slot, and customize the detail header through #detailHeader="{ mode, detailContent }"; with empty content, both fall back to the built-in ones. Clicking the back button of the detail header emits backWard.

工作区占位
Code
<script setup lang="ts">
    import { shallowRef, type Component } from 'vue';
    import { Annotation, Sidebar, type AnnotationInfo, type ImageUploadNodeOptions, type SideBarDetailContent } from '@fibrous/semi-ai-vue';
    import { IconBriefStroked, IconCodeStroked, IconModalStroked, IconSearch } from '@fibrous/semi-icons-vue';

    const { FileContent, CodeContent } = Sidebar;
    const { AnnotationContent } = Annotation;

    const containerStyle = {
        display: 'flex',
        height: '800px',
        border: '1px solid var(--semi-color-border)',
        borderRadius: '8px',
        overflow: 'hidden',
        boxSizing: 'border-box',
    } as const;

    const optionList = [
        {
            name: '查看搜索',
            key: 'searchResult',
        },
        {
            name: '文件预览',
            key: 'filePreview',
        },
        {
            name: '代码预览',
            key: 'codePreview',
        },
        {
            name: '浏览器',
            key: 'network',
        },
    ];

    const optionIcons: Record<string, Component> = {
        searchResult: IconSearch,
        filePreview: IconBriefStroked,
        codePreview: IconCodeStroked,
        network: IconModalStroked,
    };

    const defaultCodes = [
        {
            name: 'Component.js',
            key: 'code1',
            language: 'javascript',
            content: `import React from 'react';
import { AutoComplete } from '@fibrous/semi-ui-react';
import { IconSearch } from '@fibrous/semi-icons-react';

() => {
    const [stringData, setStringData] = useState([]);
    const [value, setValue] = useState('');
    const handleStringSearch = (value) => {
        let result;
        if (value) {
            result = ['gmail.com', '163.com', 'qq.com'].map(domain => value+domain);
        } else {
            result = [];
        }
        setStringData(result);
    };

    const handleChange = (value) => {
        console.log('onChange', value);
        setValue(value);
    };
    return (
        <AutoComplete
            data={stringData}
            value={value}
            showClear
            prefix={<IconSearch />}
            placeholder="搜索... "
            onSearch={handleStringSearch}
            onChange={handleChange}
            style={{ width: 200 }}
        />
    );
};
`,
        },
        {
            name: 'Style.css',
            key: 'code2',
            language: 'css',
            content: `.semi-animation-react-demo-auto {
    button {
        height: 50px;
        border: 0;
        cursor: pointer !important;
        background: #777;
        color: white;
        outline: none;
        -webkit-appearance: none;
    }

    button:hover {
        background: #878787;
    }

    .auto-main {
        display: grid;
        grid-template-columns: repeat(3, 1fr);
        grid-template-rows: auto 1fr;
        background: #575757;
    }

    .content {
        grid-column: span 3;
    }

    .item {
        background: indianred;
        width: 100%;
        overflow: hidden;
        color: white;
    }

    .item p {
        margin: 0;
        padding: 10px;
    }
}
`,
        },
        {
            name: 'Chart.json',
            key: 'code3',
            isJson: true,
            language: 'html',
            content: `{
    "axisX": {
        "title": {
            "visible": false,
            "position": "center"
        },
        "label": {
            "visible": true,
            "style": {
                "fontSize": 12,
                "fontWeight": 400,
                "lineHeight": 16,
                "fontFamily": [
                    "Inter"
                ],
                "fill": "rgba(0, 0, 0, 0.47843137254901963)"
            },
            "space": 12
        },
        "domainLine": {
            "visible": true,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(0, 0, 0, 0.12156862745098039)",
                "lineDash": []
            }
        },
        "tick": {
            "visible": false,
            "style": {
                "lineWidth": 1,
                "stroke": "rgba(255, 255, 255, 0)"
            }
        },
        "subTick": {
            "visible": false
        },
        "grid": {
            "visible": false
        },
        "subGrid": {
            "visible": false
        }
    }
}`,
        },
    ];

    const defaultFiles = [
        {
            key: 'file1',
            name: 'Semi Design 介绍',
            content: `
<h2>
  Semi Design 介绍
</h2>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
<p>
  Semi Design 是由 <strong>抖音前端团队</strong>和MED产品设计团队设计、开发并维护的<em>设计系统</em>。作为一个全面、易用、优质的现代应用UI解决方案,Semi Design从字节跳动各业务线的复杂场景中提炼而来,目前已经支撑了近千个平台产品,服务了内外部超过10万用户,详情见https://semi.design/zh-CN/start/introduction。Semi Design的特点包括:
</p>
<ul>
  <li>
    设计简洁、现代化。
  </li>
  <li>
    提供主题方案,可深度样式定制。
  </li>
</ul>
<p>
  国际化,覆盖了简/繁体中文、英语、日语、韩语、葡萄牙语等20+种语言,日期时间组件提供全球时区支持,全部组件可自动适配阿拉伯文RTL布局。
</p>
<pre><code class="language-css">body {
  display: none;
}</code></pre>
<p>
  采用 Foundation 和 Adapter 跨框架技术方案,方便扩展。
</p>
<blockquote>
  Semi Design 是由抖音前端团队和MED产品设计团队设计、开发并维护的设计系统
  <br />
  — Semi Design
</blockquote>
`,
        },
        {
            key: 'file2',
            name: 'Semi Design DSM',
            content: `<h2>
  Semi Design DSM
</h2>
<p>Semi DSM is a design system management tool provided by Semi Design. It supports global and component-level style customization and keeps synchronization between Figma and front-end code. Suitable for teams of all sizes. Whether you need to simplify workflow, improve team collaboration, or increase productivity, we have features suitable for you.</p>
`,
        },
        {
            key: 'file3',
            name: 'React v19 Adaptation',
            content: `<h2>
  React v19 Adaptation
</h2>
<p>Since the release of React v19, React has introduced numerous underlying mechanism and API changes, including upgrades and adjustments to the render mechanism, ref, context, TypeScript types, and related deprecated APIs. To ensure that the Semi Design component library is smoothly compatible with both React v19 and lower versions, we provide the original component package @fibrous/semi-ui-react for React versions below v19, as well as a new package @fibrous/semi-ui-19 specifically adapted for React v19, so users can choose as needed. This guide will help you understand how to install, use, and the precautions to take.
Installation & Usage
If your project is using React v19, please use @fibrous/semi-ui-19. For React versions below v19, continue using @fibrous/semi-ui-react as before.</p>
`,
        },
    ];

    const logo = '/assets/placeholder/avatar-a.svg';
    const img = '/assets/root-web-sites/abstract.jpg';

    const defaultInfoList: AnnotationInfo[] = [
        {
            header: 'Semi design introduction',
            key: '1',
            annotations: [
                {
                    order: 1,
                    type: 'video',
                    duration: 4432,
                    title: 'Semi Design is a design system designed',
                    url: 'https://semi.design/',
                    logo,
                    siteName: 'Semi Design',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    img,
                },
                {
                    order: 2,
                    title: 'Quick start',
                    type: 'video',
                    duration: 56,
                    url: 'https://semi.design/',
                    detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
                {
                    order: 3,
                    title: 'Use components in a modular way',
                    url: 'https://semi.design/',
                    detail: `Semi provides esm format dist, and the css of the component is only imported by the corresponding js.
When used in Webpack, Rspack, create-react-app or Vite projects, there is no need to configure any compilation items.`,
                    logo,
                    siteName: 'Semi Design',
                    img,
                },
            ],
        },
        {
            header: 'Design resource',
            key: '2',
            annotations: [
                {
                    order: 2,
                    title: 'Semi Design resource',
                    url: 'https://semi.design/',
                    detail: 'Semi Design provides a wealth of design resources to help designers and developers collaborate efficiently. Whether you are a community user or a ByteDance internal designer, you can find UI Kit resource and Figma plug-ins that suit you here.',
                    logo,
                    siteName: 'Semi Design resource',
                    img,
                },
            ],
        },
    ];

    const imgUploadProps: ImageUploadNodeOptions = {
        action: 'https://api.semi.design/upload',
        // response is the action's result; real code reads the uploaded image URL from it
        getUploadImageSrc: () => logo,
    };

    const defaultSize = { width: '60%' };
    const mode = shallowRef('main');
    const activeKey = shallowRef('codePreview');
    const activeCodeKey = shallowRef<string | string[]>('code1');
    const activeFileKey = shallowRef<string | string[]>('file1');
    const activeReferKey = shallowRef<string | string[]>('1');
    const currentDetail = shallowRef<SideBarDetailContent>();

    const onExpand = (_event: MouseEvent, content: SideBarDetailContent, expandMode: string) => {
        mode.value = expandMode;
        currentDetail.value = content;
    };
</script>

<template>
    <div :style="containerStyle">
        <div :style="{ flexGrow: 1, flexShrink: 1, padding: '20px' }">工作区占位</div>
        <Sidebar v-model:activeKey="activeKey" :defaultSize="defaultSize" :detailContent="currentDetail" :imgUploadProps="imgUploadProps" :mode="mode" :motion="false" :options="optionList" :showClose="false" title="Agent 的工作空间" visible @backWard="(_event, backMode) => (mode = backMode)">
            <template #optionIcon="{ item }">
                <component :is="optionIcons[item.key]" />
            </template>
            <template #mainContent="{ activeKey: currentKey }">
                <AnnotationContent v-if="currentKey === 'searchResult'" v-model:activeKey="activeReferKey" :info="defaultInfoList" />
                <FileContent v-else-if="currentKey === 'filePreview'" v-model:activeKey="activeFileKey" :files="defaultFiles" @expand="onExpand" />
                <CodeContent v-else-if="currentKey === 'codePreview'" v-model:activeKey="activeCodeKey" :codes="defaultCodes" @expand="onExpand" />
                <img v-else-if="currentKey === 'network'" alt="network" src="/assets/root-web-sites/test.jpg" :style="{ width: '100%' }" />
            </template>
        </Sidebar>
    </div>
</template>

API Reference

The class, style and other undeclared attributes (such as aria-label) of Sidebar, Annotation, MCPConfigure and Container land on the .semi-sidebar-container element; when the root is named (aria-label or aria-labelledby) and no role is given, its role is group. Undeclared attributes of CodeContent, CodeItem, FileContent, FileItem and AnnotationContent land on their own root elements.

The template ref of Sidebar, Annotation, MCPConfigure and Sidebar.Container is typed SidebarContainerHandle (exported from @fibrous/semi-ai-vue); its root member is HTMLDivElement | null, and null while the container is hidden.

Container

Props

PropertyDescriptionTypeDefault
visibleWhether the container is shown; bind it with v-model:visible.booleanfalse
titlePlain-text title; the title slot takes precedence.stringundefined
motionWhether showing and hiding use the expand animation.booleantrue
resizableWhether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true.booleantrue
minWidthMinimum width when resizing; applies only when resizable is true.string | number150
maxWidthMaximum width when resizing; applies only when resizable is true.string | numberundefined
defaultSizeInitial width and height; applies only when resizable is true.Type{ width?: string | number | undefined; height?: string | number | undefined; }undefined
showCloseWhether the header shows the close button.booleantrue
closeOnEscWhether pressing Esc emits cancel.booleanfalse

Events

EventDescriptionCallback parameters
update:visibleEmitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes the container.[visible: false]
cancelEmitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true.[event: MouseEvent | KeyboardEvent]
afterVisibleChangeEmitted after the show or hide animation ends, with whether the container is visible.[visible: boolean]

Slots

SlotDescriptionScope parameters
defaultThe content area of the container.any
titleHeader title; it takes precedence over the title prop.any
headerReplaces the whole header; empty content falls back to the built-in header.any

Exposes

NameDescriptionType
rootThe .semi-sidebar-container root element; null while hidden.HTMLDivElement | null

MCPConfigure

Props

PropertyDescriptionTypeDefault
visibleWhether it is shown; bind it with v-model:visible.booleansemiGlobalDefault("MCPConfigure", "visible")
titlePlain-text title, the locale's MCP configure text by default; the title slot takes precedence.stringsemiGlobalDefault("MCPConfigure", "title")
motionWhether showing and hiding use the expand animation.booleansemiGlobalDefault("MCPConfigure", "motion")
resizableWhether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true.booleansemiGlobalDefault("MCPConfigure", "resizable")
minWidthMinimum width when resizing; applies only when resizable is true.string | numbersemiGlobalDefault("MCPConfigure", "minWidth")
maxWidthMaximum width when resizing; applies only when resizable is true.string | numbersemiGlobalDefault("MCPConfigure", "maxWidth")
defaultSizeInitial width and height; applies only when resizable is true.Type{ width?: string | number | undefined; height?: string | number | undefined; }semiGlobalDefault("MCPConfigure", "defaultSize")
showCloseWhether the header shows the close button.booleansemiGlobalDefault("MCPConfigure", "showClose")
closeOnEscWhether pressing Esc emits cancel.booleansemiGlobalDefault("MCPConfigure", "closeOnEsc")
optionsBuilt-in MCP tools; bind it with v-model:options. Each item needs a unique value.MCPConfigureOption[]semiGlobalDefault("MCPConfigure", "options")
customOptionsCustom MCP tools; bind it with v-model:customOptions.MCPConfigureOption[]semiGlobalDefault("MCPConfigure", "customOptions")
filterCustom search filter, called with the lower-cased input and an option; the label and desc are matched by default.Type((inputValue: string, option: MCPConfigureOption) => boolean)undefined
placeholderPlaceholder of the search input, the locale text by default.stringsemiGlobalDefault("MCPConfigure", "placeholder")

Events

EventDescriptionCallback parameters
update:visibleEmitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes it.[visible: false]
cancelEmitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true.[event: MouseEvent | KeyboardEvent]
afterVisibleChangeEmitted after the show or hide animation ends, with whether it is visible.[visible: boolean]
update:optionsEmitted before statusChange when a built-in tool is switched, so v-model:options follows.[options: MCPConfigureOption[]]
update:customOptionsEmitted before statusChange when a custom tool is switched, so v-model:customOptions follows.[options: MCPConfigureOption[]]
statusChangeEmitted after a tool is switched, with the list whose active flag changed and whether it is the custom list.[options: MCPConfigureOption[], custom: boolean]
searchEmitted when the search input changes, with the input value and whether the custom list is shown.[inputValue: string, custom: boolean]
addClickEmitted when the add button of the custom page is clicked.[event: MouseEvent]
configureClickEmitted when the configure button is clicked, with the event and its option.[event: MouseEvent, option: MCPConfigureOption]
editClickEmitted when the edit button of a custom tool is clicked, with the event and its option.[event: MouseEvent, option: MCPConfigureOption]

Slots

SlotDescriptionScope parameters
titleHeader title; it takes precedence over the title prop.any
headerReplaces the whole header; empty content falls back to the built-in header.any
iconIcon of an option, with item, index and custom. When provided it is used for every option; the icon field is an image URL only when it is absent.MCPConfigureItemSlotProps
descDescription of an option, with item, index and custom; the desc field is shown when absent.MCPConfigureItemSlotProps
itemReplaces the whole built-in row, with item, index and custom.MCPConfigureItemSlotProps

Exposes

NameDescriptionType
rootThe .semi-sidebar-container root element; null while hidden.HTMLDivElement | null

MCPConfigureOption

PropertyDescriptionTypeDefault
activeWhether this MCP is activebooleanfalse
configureWhether to show the configure buttonbooleanfalse
descDescription text, matched by the built-in filter; use the #desc slot for other contentstring-
disabledWhether this MCP is disabled. When true, users cannot toggle its active statebooleanfalse
iconImage URL of the icon; use the #icon slot for other contentstring-
labelLabel textstring-
valueValue, required. Identifies the option in statusChange and is used as the item key, so it must be unique in a liststring-

Annotation

Props

PropertyDescriptionTypeDefault
visibleWhether it is shown; bind it with v-model:visible.booleansemiGlobalDefault("Annotation", "visible")
titlePlain-text title, the locale's references text by default; the title slot takes precedence.stringsemiGlobalDefault("Annotation", "title")
motionWhether showing and hiding use the expand animation.booleansemiGlobalDefault("Annotation", "motion")
resizableWhether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true.booleansemiGlobalDefault("Annotation", "resizable")
minWidthMinimum width when resizing; applies only when resizable is true.string | numbersemiGlobalDefault("Annotation", "minWidth")
maxWidthMaximum width when resizing; applies only when resizable is true.string | numbersemiGlobalDefault("Annotation", "maxWidth")
defaultSizeInitial width and height; applies only when resizable is true.Type{ width?: string | number | undefined; height?: string | number | undefined; }semiGlobalDefault("Annotation", "defaultSize")
showCloseWhether the header shows the close button.booleansemiGlobalDefault("Annotation", "showClose")
closeOnEscWhether pressing Esc emits cancel.booleansemiGlobalDefault("Annotation", "closeOnEsc")
activeKeyKeys of the expanded groups; bind it with v-model:activeKey.string | string[]semiGlobalDefault("Annotation", "activeKey")
infoGroups of references; each has a header, a key and its annotations.AnnotationInfo[]semiGlobalDefault("Annotation", "info")

Events

EventDescriptionCallback parameters
update:visibleEmitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes it.[visible: false]
cancelEmitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true.[event: MouseEvent | KeyboardEvent]
afterVisibleChangeEmitted after the show or hide animation ends, with whether it is visible.[visible: boolean]
update:activeKeyEmitted before change when a group opens or closes, so v-model:activeKey follows.[activeKey: string[]]
changeEmitted when a group opens or closes, with the expanded keys.[activeKey: string | string[]]
clickEmitted when a reference is clicked, with the event and its item; the native click of the root is not reported apart from it.[event: MouseEvent, item: AnnotationItem]

Slots

SlotDescriptionScope parameters
titleHeader title; it takes precedence over the title prop.any
headerReplaces the whole container header; empty content falls back to the built-in header.any
infoHeaderContent of a group header after its icon, with item and index; the header field is shown when absent.AnnotationHeaderSlotProps
itemReplaces the built-in reference item, with item and index (its position in the group).AnnotationItemSlotProps

Exposes

NameDescriptionType
rootThe .semi-sidebar-container root element; null while hidden.HTMLDivElement | null

AnnotationContent

Props

PropertyDescriptionTypeDefault
activeKeyKeys of the expanded groups; bind it with v-model:activeKey.string | string[]undefined
infoGroups of references; each has a header, a key and its annotations.AnnotationInfo[][]

Events

EventDescriptionCallback parameters
update:activeKeyEmitted before change when a group opens or closes, so v-model:activeKey follows.[activeKey: string[]]
changeEmitted when a group opens or closes, with the expanded keys.[activeKey: string | string[]]
clickEmitted when a reference is clicked, with the event and its item; the native click of the root is not reported apart from it.[event: MouseEvent, item: AnnotationItem]

Slots

SlotDescriptionScope parameters
headerContent of a group header after its icon, with item and index; the header field is shown when absent.AnnotationHeaderSlotProps
itemReplaces the built-in reference item, with item and index (its position in the group).AnnotationItemSlotProps

Exposes

NameDescriptionType
None

AnnotationInfo

PropertyDescriptionTypeDefault
annotationsReference items of the groupAnnotationItem[]-
headerPlain text of the group header; customize it with the #infoHeader slot (Annotation) or the #header slot (AnnotationContent)string-
keyUnique key of the groupstring-

AnnotationItem

PropertyDescriptionTypeDefault
detailExtra detail text such as video description or text notestring-
durationDuration, usually used for videos, in secondsnumber-
imgImage url, such as video cover or illustrationstring-
logoLogo url of the site/platform to which the content belongsstring-
orderOrder/index numbernumber-
siteNameName of the site/platform where the content belongsstring-
titleTitlestring-
typeContent type'video' | 'text'-
urlResource url, opened in a new tab. An item without it renders a link without href that only the pointer can activatestring-

Props

PropertyDescriptionTypeDefault
modeDisplay mode: main is the main view, code and file use the built-in details, and any other string is rendered by the detailContent slot.stringsemiDefault("Sidebar", "mode", strings.MODE.MAIN)
activeKeyKey of the selected option in the main view; bind it with v-model:activeKey.stringsemiGlobalDefault("Sidebar", "activeKey")
optionsOption buttons at the top of the main view, each with a name and a key; icons use the optionIcon slot.SideBarOption[]semiGlobalDefault("Sidebar", "options")
detailContentThe item shown in code and file modes: the CodeItem or FileItem props plus a key; a new key remounts it. In file mode its editable and imgUploadProps have no effect, as fileEditable and imgUploadProps decide them.SideBarDetailContentsemiGlobalDefault("Sidebar", "detailContent")
fileEditableWhether the rich text in file mode is editable.booleansemiDefault("Sidebar", "fileEditable", true)
imgUploadPropsImage upload options of file mode, read when the editor is created; later changes have no effect.ImageUploadNodeOptionssemiGlobalDefault("Sidebar", "imgUploadProps")
visibleWhether it is shown; bind it with v-model:visible.booleansemiGlobalDefault("Sidebar", "visible")
titlePlain-text title of the main view; the title slot takes precedence. Detail views use the detail header.stringsemiGlobalDefault("Sidebar", "title")
motionWhether showing and hiding use the expand animation.booleansemiGlobalDefault("Sidebar", "motion")
resizableWhether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true.booleansemiGlobalDefault("Sidebar", "resizable")
minWidthMinimum width when resizing; applies only when resizable is true.string | numbersemiGlobalDefault("Sidebar", "minWidth")
maxWidthMaximum width when resizing; applies only when resizable is true.string | numbersemiGlobalDefault("Sidebar", "maxWidth")
defaultSizeInitial width and height; applies only when resizable is true.Type{ width?: string | number | undefined; height?: string | number | undefined; }semiGlobalDefault("Sidebar", "defaultSize")
showCloseWhether the header shows the close button.booleansemiGlobalDefault("Sidebar", "showClose")
closeOnEscWhether pressing Esc emits cancel.booleansemiGlobalDefault("Sidebar", "closeOnEsc")

Events

EventDescriptionCallback parameters
update:activeKeyEmitted before activeOptionChange when an option is clicked, so v-model:activeKey follows.[activeKey: string]
activeOptionChangeEmitted when an option is clicked, with the event and the option's key.[event: MouseEvent, activeKey: string]
backWardEmitted when the back button of the detail header is clicked, with the event and main.[event: MouseEvent, mode: string]
detailContentCopyEmitted after the copy button wrote to the clipboard, with the event, the content and whether it succeeded.[event: MouseEvent, content: string, success: boolean]
fileContentChangeEmitted after an edit in file mode, with the content as HTML.[content: string]
update:visibleEmitted before cancel when the close button or Esc cancels, with false, so v-model:visible closes it.[visible: false]
cancelEmitted when the close button is clicked, or when Esc is pressed while closeOnEsc is true.[event: MouseEvent | KeyboardEvent]
afterVisibleChangeEmitted after the show or hide animation ends, with whether it is visible.[visible: boolean]

Slots

SlotDescriptionScope parameters
titleTitle of the main view; it takes precedence over the title prop.any
optionIconIcon of the built-in option button, with item and index.SideBarOptionSlotProps
optionItemReplaces the whole option button, with item, index, active and onClick (which selects the option).SideBarOptionItemSlotProps
mainContentContent below the options in the main view, with activeKey.SideBarMainContentSlotProps
detailHeaderHeader in detail modes, with mode and detailContent; empty content falls back to the built-in header.SideBarDetailHeaderSlotProps
detailContentContent in detail modes, with mode; empty content falls back to the built-in code or file detail.SideBarDetailContentSlotProps
customRenderForwarded to the customRender slot of the JsonViewer in the built-in code detail, for the content matched by customRenderRule.JsonViewerCustomRenderSlotProps
searchButtonForwarded to the searchButton slot of the JsonViewer in the built-in code detail, replacing its search button.JsonViewerSearchButtonSlotProps

Exposes

NameDescriptionType
rootThe .semi-sidebar-container root element; null while hidden.HTMLDivElement | null

SideBarOption

PropertyDescriptionTypeDefault
keyUnique key of the optionstring-
nameOption name; use the #optionIcon slot for the iconstring-

CodeContent

Each item of codes is the props of CodeItem plus a key that identifies its panel.

Props

PropertyDescriptionTypeDefault
codesThe code entries, each with the CodeItem props and a key identifying its panel.CodeItemData[][]
activeKeyKeys of the expanded code panels; bind it with v-model:activeKey.string | string[]undefined

Events

EventDescriptionCallback parameters
update:activeKeyEmitted before change when a panel opens or closes, so v-model:activeKey follows.[activeKey: string[]]
changeEmitted when a panel opens or closes through its arrow, with the expanded keys.[activeKey: string | string[]]
expandEmitted when the expand button beside a panel header is clicked, with the event, its entry and code. The button is only rendered when this event is bound.[event: MouseEvent, item: CodeItemData, mode: string]

Slots

SlotDescriptionScope parameters
customRenderForwarded to the customRender slot of the JsonViewer in every JSON panel.JsonViewerCustomRenderSlotProps
searchButtonForwarded to the searchButton slot of the JsonViewer in every JSON panel, replacing its search button.JsonViewerSearchButtonSlotProps

Exposes

NameDescriptionType
None

CodeItem

Props

PropertyDescriptionTypeDefault
nameName of the code item, shown by the CodeContent panel header and the Sidebar detail header; CodeItem itself does not render it.stringundefined
languageLanguage name as in the CodeHighlight language prop; register it with CodeHighlight.register first, otherwise plain text is shown.stringundefined
contentThe code or JSON string.stringundefined
isJsonWhen true the content is shown by JsonViewer, otherwise by CodeHighlight.booleanfalse
jsonViewerPropsOther props for JsonViewer, plus an extra class and style. modelValue (the content), width and height (100%), options (read-only, auto wrap) and showSearch (false) have defaults; a prop given here replaces its default as a whole.Type(Partial<JsonViewerProps> & ElementLook)undefined
codeHighlightPropsOther props for CodeHighlight, plus an extra class and style.Type(Partial<CodeHighlightProps> & ElementLook)undefined

Events

EventDescriptionCallback parameters
None

Slots

SlotDescriptionScope parameters
customRenderThe customRender slot of JsonViewer, for the content matched by jsonViewerProps.options.customRenderRule.JsonViewerCustomRenderSlotProps
searchButtonThe searchButton slot of JsonViewer, replacing its search button.JsonViewerSearchButtonSlotProps

Exposes

NameDescriptionType
None

FileContent

Each item of files is the props of FileItem plus a key that identifies its panel. It is rendered read-only: each entry's extensions and imgUploadProps reach its preview.

Props

PropertyDescriptionTypeDefault
filesThe file entries, rendered read-only: each entry's extensions and imgUploadProps reach its preview.FileItemData[][]
activeKeyKeys of the expanded file panels; bind it with v-model:activeKey.string | string[]undefined

Events

EventDescriptionCallback parameters
update:activeKeyEmitted before change when a panel opens or closes, so v-model:activeKey follows.[activeKey: string[]]
changeEmitted when a panel opens or closes through its arrow, with the expanded keys.[activeKey: string | string[]]
expandEmitted when the expand button beside a panel header is clicked, with the event, its entry and file. The button is only rendered when this event is bound.[event: MouseEvent, item: FileItemData, mode: string]

Slots

SlotDescriptionScope parameters
None

Exposes

NameDescriptionType
None

FileItem

Props

PropertyDescriptionTypeDefault
nameFile name, used as the accessible name of the editing area; later changes are synced to the editor.stringundefined
contentRich text as HTML. Later changes are synced to the editor; content equal to the editor's is not reset, and syncing does not emit contentChange.stringundefined
editableWhether it is editable; later changes are synced to the editor.booleantrue
extensionstiptap extensions appended to the built-in ones, read when the editor is created; later changes have no effect.Extensions[]
imgUploadPropsImage upload options, read when the editor is created; later changes have no effect.ImageUploadNodeOptionsundefined

Events

EventDescriptionCallback parameters
contentChangeEmitted after an edit, with the content as HTML.[content: string]

Slots

SlotDescriptionScope parameters
None

Exposes

NameDescriptionType
None