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
import { Annotation, MCPConfigure, Sidebar } from '@fibrous/semi-ai-react';
const { Container, CodeContent, CodeItem, FileContent, FileItem } = Sidebar;
const { AnnotationContent } = Annotation;
Basic Container
The basic container of the Sidebar is the base container for MCP configuration, References and Sidebar.
visibletogether withonCancelis used to control show/hidetitlesets the titlemotionsets whether to enable the expand animationresizablesets whether the width is resizable. Whentrue, you can useminWidthandmaxWidthto control min and max width
Code
import { useState, useCallback, type CSSProperties } from 'react';
import { Sidebar } from '@fibrous/semi-ai-react';
import { Button, Switch } from '@fibrous/semi-ui-react';
const { Container } = Sidebar;
const containerStyle: CSSProperties = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
borderRadius: 8,
overflow: 'hidden',
boxSizing: 'border-box',
};
export default function SidebarDemo() {
const [visible, setVisible] = useState(true);
const [motion, setMotion] = useState(true);
const [resizable, setResizable] = useState(true);
const toggleVisible = useCallback(() => {
setVisible((visible) => !visible);
}, []);
const onMotionChange = useCallback((checked: boolean) => {
setMotion(checked);
}, []);
const onResizableChange = useCallback((checked: boolean) => {
setResizable(checked);
}, []);
return (
<div style={containerStyle}>
<div style={{ flexGrow: 1, flexShrink: 1, padding: 20 }}>
<div>
<Button aria-pressed={visible} onClick={toggleVisible}>
显示容器
</Button>
<div style={{ display: 'flex', alignItems: 'center', marginTop: 10 }}>
<span id="sidebar-container-motion">是否有动画</span> <Switch aria-labelledby="sidebar-container-motion" checked={motion} onChange={onMotionChange} />
</div>
<div style={{ display: 'flex', alignItems: 'center', marginTop: 10 }}>
<span id="sidebar-container-resizable">是否可伸缩</span> <Switch aria-labelledby="sidebar-container-resizable" checked={resizable} onChange={onResizableChange} />
</div>
</div>
</div>
<Container motion={motion} resizable={resizable} minWidth={250} maxWidth="60%" visible={visible} title="基础容器示例" style={resizable ? {} : { width: 200 }} onCancel={toggleVisible} />
</div>
);
}MCP Configuration
Use MCPConfigure to display, enable/disable, configure and search MCP tools.
- Use
optionsandcustomOptionsto set built-in MCP tools and custom MCP tools - Use
visibleto control show and hide, andonCancelto listen to user close behavior - Use
onStatusChangeto handle enabling/disabling of MCP tools - Use
onAddClickto handle actions after clicking the Add button in custom MCP page - Use
onConfigureClickto listen to configuration of built-in MCP tools, andonEditClickto listen to configuration of custom MCP tools
For other APIs of MCPConfigure, see MCPConfigure.
The type of MCP tool item is as follows:
interface MCPOption {
icon?: ReactNode;
label?: string;
value: string; // required, identifies the tool and must be unique
desc?: ReactNode;
active?: boolean;
disabled?: boolean;
configure?: boolean; // whether to show configure button
}
Usage example:
Code
import { useState, useCallback, useRef, type CSSProperties, type MouseEvent, type RefObject } from 'react';
import { MCPConfigure, type MCPConfigureOption as MCPOption } from '@fibrous/semi-ai-react';
import { IconSemiLogo, IconFigma } from '@fibrous/semi-icons-react';
import { Button, Modal, Form, type FormHandle } from '@fibrous/semi-ui-react';
interface McpFormValues {
name: string;
src: string;
desc: string;
}
interface CustomOptionCreateModelProps {
visible: boolean;
handleOk: () => void;
handleCancel: () => void;
formRef: RefObject<FormHandle<McpFormValues> | null>;
}
const defaultOptions: MCPOption[] = [
{
icon: <IconSemiLogo />,
value: 'Semi mcp',
label: 'Semi',
configure: true,
desc: '支持 Semi 的文档、源码搜索,辅助开发',
},
{
icon: <IconFigma />,
value: 'figma',
label: 'Figma',
desc: 'Figma MCP Server 连接Figma与AI开发工具的功能。它通过标准化的模型上下文协MCP),将组件、变量等设计数据和上下文暴露给AI,从而实现从设计稿到代码的智能生成,显著提升开发效率。',
},
];
const CustomOptionCreateModel = ({ visible, handleOk, handleCancel, formRef }: CustomOptionCreateModelProps) => {
return (
<Modal title="自定义 MCP" visible={visible} onOk={handleOk} onCancel={handleCancel} closeOnEsc>
<Form ref={formRef} layout="vertical" onValueChange={(values) => console.log(values)}>
<Form.Input rules={[{ required: true, message: '请输入 MCP 名称' }]} field="name" label="MCP 名称" style={{ width: '100%' }} />
<Form.Input
initValue="/assets/placeholder/avatar-a.svg"
rules={[
{ required: true, message: '请输入 MCP 图标 URL' },
{
validator: (_rule, value) => {
const urlRegex = /^(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+(?::\d+)?(?:\/[^\s]*)?$/i;
return urlRegex.test(value);
},
message: '请输入有效的 MCP 图标 URL',
},
]}
field="src"
label="MCP 图标 URL"
style={{ width: '100%' }}
/>
<Form.TextArea rules={[{ required: true, message: '请输入 MCP 介绍' }]} field="desc" label="MCP 介绍" style={{ width: '100%' }} />
</Form>
</Modal>
);
};
let index = 1;
const containerStyle: CSSProperties = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
borderRadius: 8,
overflow: 'hidden',
boxSizing: 'border-box',
};
export default function SidebarDemo() {
const [visible, setVisible] = useState(true);
const toggleVisible = useCallback(() => {
setVisible((visible) => !visible);
}, []);
const [options, setOptions] = useState(defaultOptions);
const [mVisible, setMVisible] = useState(false);
const [customOptions, setCustomOptions] = useState<MCPOption[]>([]);
const formRef = useRef<FormHandle<McpFormValues>>(null);
const handleOk = useCallback(() => {
formRef.current?.formApi
.validate()
.then((values) => {
const newOptions = [
...customOptions,
{
label: values.name,
icon: values.src,
value: `mcp-${index++}`,
desc: values.desc,
},
];
setCustomOptions(newOptions);
setMVisible(false);
})
.catch((errors) => {
console.log('errors', errors);
});
}, [customOptions]);
const showDialog = useCallback(() => {
setMVisible(true);
}, []);
const handleCancel = useCallback(() => {
setMVisible(false);
}, []);
const onStatusChange = useCallback((options: MCPOption[], custom: boolean) => {
if (custom) {
setCustomOptions(options);
} else {
setOptions(options);
}
}, []);
const onAddClick = useCallback(() => {
showDialog();
}, [showDialog]);
const onConfigureClick = useCallback((_e: MouseEvent, option: MCPOption) => {
console.log('configure click', option);
}, []);
const onEditClick = useCallback((_e: MouseEvent, option: MCPOption) => {
console.log('edit click', option);
}, []);
return (
<div style={containerStyle}>
<div style={{ flexGrow: 1, flexShrink: 1, padding: 20 }}>
<Button aria-pressed={visible} onClick={toggleVisible}>
MCP 配置
</Button>
</div>
<MCPConfigure style={{ width: 500 }} resizable={false} visible={visible} onCancel={toggleVisible} options={options} customOptions={customOptions} onStatusChange={onStatusChange} onAddClick={onAddClick} onConfigureClick={onConfigureClick} onEditClick={onEditClick} />
<CustomOptionCreateModel formRef={formRef} visible={mVisible} handleOk={handleOk} handleCancel={handleCancel} />
</div>
);
}References
Use the Annotation component to manage the display of reference sources.
- Use
activeKeytogether withonChangeto manage the currently expanded item infosets the reference content list
Code
import { useState, useCallback, type ComponentProps, type CSSProperties, type MouseEvent } from 'react';
import { Annotation, type AnnotationItem } from '@fibrous/semi-ai-react';
import { Button } from '@fibrous/semi-ui-react';
const containerStyle: CSSProperties = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
borderRadius: 8,
overflow: 'hidden',
boxSizing: 'border-box',
};
const defaultInfoList: ComponentProps<typeof Annotation>['info'] = [
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design',
detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
img: '/assets/root-web-sites/abstract.jpg',
},
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design',
img: '/assets/root-web-sites/abstract.jpg',
},
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design',
img: '/assets/root-web-sites/abstract.jpg',
},
],
},
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design resource',
img: '/assets/root-web-sites/abstract.jpg',
},
],
},
];
export default function SidebarDemo() {
const [visible, setVisible] = useState(true);
const [activeKey, setActiveKey] = useState<string | string[]>('1');
const toggleVisible = useCallback(() => {
setVisible((visible) => !visible);
}, []);
const onChange = useCallback((key: string | string[]) => {
console.log('onChange', key);
setActiveKey(key);
}, []);
const onClick = useCallback((e: MouseEvent, item: AnnotationItem) => {
console.log('onClick', e, item);
}, []);
return (
<div style={containerStyle}>
<div style={{ flexGrow: 1, flexShrink: 1, padding: 20 }}>
<Button aria-pressed={visible} onClick={toggleVisible}>
参考来源
</Button>
</div>
<Annotation defaultSize={{ width: 420 }} visible={visible} onCancel={toggleVisible} activeKey={activeKey} info={defaultInfoList} onChange={onChange} onClick={onClick} />
</div>
);
}Code Display
You can use CodeItem in Sidebar to display code. CodeItem is built based on JsonViewer and CodeHighlight.
content: content stringisJson: whether the content is jsonlanguage: programming language name, same aslanguageinCodeHighlight; register it withCodeHighlight.registerfirstjsonViewerProps: configure other JsonViewer propscodeHighlightProps: configure other CodeHighlight props
Code
import { useState, useCallback } from 'react';
import { Sidebar } from '@fibrous/semi-ai-react';
import { RadioGroup, Radio, type RadioChangeEvent } from '@fibrous/semi-ui-react';
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,
};
export default function SidebarDemo() {
const [type, setType] = useState('json');
const onRadioChange = useCallback((e: RadioChangeEvent) => {
setType(e.target.value);
}, []);
return (
<>
<RadioGroup type="button" buttonSize="middle" value={type} onChange={onRadioChange} style={{ marginBottom: 10 }}>
<Radio value="json">JSON</Radio>
<Radio value="css">CSS</Radio>
</RadioGroup>
<div style={{ height: 200, overflow: 'auto' }}>
<CodeItem {...(type === 'json' ? jsonProps : codeProps)} />
</div>
</>
);
}Code List
You can use CodeContent in Sidebar to display a list of code blocks.
- Use
activeKeytogether withonChangeto manage the expanded panels - Use
onExpandto listen to the expand button in a panel header
Code
import { useState, useCallback } from 'react';
import { Sidebar } from '@fibrous/semi-ai-react';
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
}
}
}`,
},
];
export default function SidebarDemo() {
const [activeKey, setActiveKey] = useState<string | string[]>('code1');
const onChange = useCallback((key: string | string[]) => {
setActiveKey(key);
}, []);
return (
<div className="semi-sidebar-main">
<CodeContent style={{ width: 600 }} activeKey={activeKey} codes={defaultCodes} onChange={onChange} />
</div>
);
}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 content, supports the same types as TiptapContent. 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 callonContentChangeeditable: whether the content is editable; a change after mount is synced to the editorimgUploadProps: configure image upload endpoint and how to set the src after upload. Useactionto set upload url andgetUploadImageSrc(response)to return the uploaded image url from the upload response (when omitted, a string response is used as the url, otherwiseresponse.src), which will be used as src of img node in rich text. The toolbar shows the image button only whenactionorcustomRequestis set
Code
import { useState, useCallback } from 'react';
import { Sidebar, type ImageUploadNodeOptions } from '@fibrous/semi-ai-react';
import { Button } from '@fibrous/semi-ui-react';
const { FileItem } = Sidebar;
const defaultFileContent = `<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',
getUploadImageSrc: () => {
// response is the action's result; real code reads the uploaded image URL from it
return '/assets/placeholder/avatar-a.svg';
},
};
export default function SidebarDemo() {
const [editable, setEditable] = useState(true);
const [content] = useState(defaultFileContent);
const toggleEditable = useCallback(() => {
setEditable((editable) => !editable);
}, []);
return (
<>
<Button aria-pressed={editable} onClick={toggleEditable}>
可编辑
</Button>
<br />
<br />
<FileItem name="Semi Design 介绍" content={content} editable={editable} style={{ border: '1px solid var(--semi-color-border)', padding: 12 }} imgUploadProps={imgUploadProps} />
</>
);
}Rich Text List
You can use FileContent in Sidebar to display a list of rich text documents.
- Use
activeKeytogether withonChangeto manage the expanded panels - Use
onExpandto listen to the expand button in a panel header
Code
import { useState, useCallback } from 'react';
import { Sidebar } from '@fibrous/semi-ai-react';
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>
`,
},
];
export default function SidebarDemo() {
const [activeKey, setActiveKey] = useState<string | string[]>('file1');
const onChange = useCallback((key: string | string[]) => {
setActiveKey(key);
}, []);
return (
<div className="semi-sidebar-main">
<FileContent style={{ width: 600 }} activeKey={activeKey} files={defaultFiles} onChange={onChange} />
</div>
);
}Sidebar
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, decide whether to show close button through showClose, and configure top button group through options.
For content rendering in the main view, you can pass a render function via renderMainContent. 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. If you want to customize how the detail view is rendered, you can use renderDetailContent to handle it yourself.
Code
import { useState, useCallback, type ComponentProps, type CSSProperties, type MouseEvent } from 'react';
import { Sidebar, Annotation, type CodeItemProps, type FileItemProps, type ImageUploadNodeOptions } from '@fibrous/semi-ai-react';
import { IconSearch, IconBriefStroked, IconCodeStroked, IconModalStroked } from '@fibrous/semi-icons-react';
const { FileContent, CodeContent } = Sidebar;
const { AnnotationContent } = Annotation;
const containerStyle: CSSProperties = {
display: 'flex',
height: '800px',
border: '1px solid var(--semi-color-border)',
borderRadius: 8,
overflow: 'hidden',
boxSizing: 'border-box',
};
const optionList = [
{
icon: <IconSearch />,
name: '查看搜索',
key: 'searchResult',
},
{
icon: <IconBriefStroked />,
name: '文件预览',
key: 'filePreview',
},
{
icon: <IconCodeStroked />,
name: '代码预览',
key: 'codePreview',
},
{
icon: <IconModalStroked />,
name: '浏览器',
key: 'network',
},
];
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 defaultInfoList: ComponentProps<typeof AnnotationContent>['info'] = [
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design',
detail: ' As a comprehensive, easy-to-use, and high-quality modern enterprise-level application UI solution',
img: '/assets/root-web-sites/abstract.jpg',
},
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design',
img: '/assets/root-web-sites/abstract.jpg',
},
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design',
img: '/assets/root-web-sites/abstract.jpg',
},
],
},
{
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: '/assets/placeholder/avatar-a.svg',
siteName: 'Semi Design resource',
img: '/assets/root-web-sites/abstract.jpg',
},
],
},
];
const imgUploadProps: ImageUploadNodeOptions = {
action: 'https://api.semi.design/upload',
getUploadImageSrc: () => {
// response is the action's result; real code reads the uploaded image URL from it
return '/assets/placeholder/avatar-a.svg';
},
};
export default function SidebarDemo() {
const [mode, setMode] = useState('main');
const [activeKey, setActiveKey] = useState('codePreview');
const [activeCodeKey, setActiveCodeKey] = useState<string | string[]>('code1');
const [activeFileKey, setActiveFileKey] = useState<string | string[]>('file1');
const [activeReferKey, setActiveReferKey] = useState<string | string[]>('1');
const [currentDetail, setCurrentDetail] = useState<CodeItemProps | FileItemProps>();
const onExpand = useCallback((_e: MouseEvent, content: CodeItemProps | FileItemProps, mode: string) => {
setMode(mode);
setCurrentDetail(content);
}, []);
const onActiveCodeKeyChange = useCallback((codeKey: string | string[]) => {
setActiveCodeKey(codeKey);
}, []);
const onActiveFileKeyChange = useCallback((fileKey: string | string[]) => {
setActiveFileKey(fileKey);
}, []);
const onActiveReferKeyChange = useCallback((referKey: string | string[]) => {
setActiveReferKey(referKey);
}, []);
const renderMainContent = useCallback(
(activeKey: string) => {
switch (activeKey) {
case 'searchResult':
return <AnnotationContent activeKey={activeReferKey} info={defaultInfoList} onChange={onActiveReferKeyChange} />;
case 'filePreview':
return <FileContent activeKey={activeFileKey} files={defaultFiles} onExpand={onExpand} onChange={onActiveFileKeyChange} />;
case 'codePreview':
return <CodeContent activeKey={activeCodeKey} codes={defaultCodes} onExpand={onExpand} onChange={onActiveCodeKeyChange} />;
case 'network':
return <img alt="network" src="/assets/root-web-sites/test.jpg" style={{ width: '100%' }} />;
default:
return;
}
},
[activeCodeKey, activeFileKey, activeReferKey, onExpand, onActiveCodeKeyChange, onActiveFileKeyChange, onActiveReferKeyChange]
);
const onActiveOptionChange = useCallback((_e: MouseEvent, key: string) => {
setActiveKey(key);
}, []);
const onBackWard = useCallback((_e: MouseEvent, mode: string) => {
setMode(mode);
}, []);
return (
<div style={containerStyle}>
<div style={{ flexGrow: 1, flexShrink: 1, padding: 20 }}>工作区占位</div>
<Sidebar
showClose={false}
visible
motion={false}
title="Agent 的工作空间"
mode={mode}
defaultSize={{ width: '60%' }}
onActiveOptionChange={onActiveOptionChange}
activeKey={activeKey}
options={optionList}
onBackWard={onBackWard}
renderMainContent={renderMainContent}
detailContent={currentDetail}
imgUploadProps={imgUploadProps}
/>
</div>
);
}API Reference
Container
Props
| Property | Description | Type | Default |
|---|---|---|---|
| afterVisibleChange | Called after a visibility change has completed, with whether the container is visible; with motion it runs when the animation ends. | Type(isVisible: boolean) => void | - |
| children | Content of the container. | React.ReactNode | - |
| closeOnEsc | Whether pressing Esc calls onCancel, false by default. | boolean | - |
| containerRef | Receives the root element (.semi-sidebar-container), as ref does. | TypeReact.RefObject<HTMLDivElement> | - |
| defaultSize | Initial size (width and height); applies only when resizable is true. | { width?: number | string; height?: number | string } | - |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | - |
| minWidth | Minimum width when resizing; applies only when resizable is true, 150 by default. | string | number | - |
| motion | Whether showing and hiding use the expand animation, true by default. | boolean | - |
| onCancel | Called when the close button is clicked, or when Esc is pressed while closeOnEsc is true, with the event. | Type(e: any) => void | - |
| ref | Reference to the root element (.semi-sidebar-container); null after it is hidden and its leave animation has ended. | TypeReact.Ref<HTMLDivElement> | - |
| renderHeader | Renders the whole header; the built-in header is used when it returns no content. | Type() => ReactNode | - |
| resizable | Whether the width can be resized by dragging, true by default; minWidth, maxWidth and defaultSize apply only when true. | boolean | - |
| showClose | Whether the header shows the close button, true by default. | boolean | - |
| style | Inline style of the root element. | CSSProperties | - |
| title | Title in the header; any content. | ReactNode | - |
| visible | Whether the container is shown. | boolean | - |
The class name (className) and other native attributes (such as data-* and aria-label) land on the root element .semi-sidebar-container; when only aria-label is set without role, the root element's role is group.
MCPConfigure
Props
| Property | Description | Type | Default |
|---|---|---|---|
| afterVisibleChange | Called after a visibility change has completed, with whether the container is visible; with motion it runs when the animation ends. | Type(isVisible: boolean) => void | - |
| children | Has no effect; the content is the MCP tool list. | React.ReactNode | - |
| closeOnEsc | Whether pressing Esc calls onCancel, false by default. | boolean | - |
| containerRef | Receives the root element (.semi-sidebar-container), as ref does. | TypeReact.RefObject<HTMLDivElement> | - |
| customOptions | Custom MCP tools, listed on the custom tab; each item needs a unique value. | MCPReactOption[] | - |
| defaultSize | Initial size (width and height); applies only when resizable is true. | { width?: number | string; height?: number | string } | - |
| filter | Custom search filter, called with the lower-cased input and an option; the label and desc are matched by default. | Type(inputValue: string, option: MCPReactOption) => boolean | - |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | - |
| minWidth | Minimum width when resizing; applies only when resizable is true, 150 by default. | string | number | - |
| motion | Whether showing and hiding use the expand animation, true by default. | boolean | - |
| onAddClick | Called when the add button on the custom tab is clicked, with the event. | Type(e: React.MouseEvent<HTMLButtonElement>) => void | - |
| onCancel | Called when the close button is clicked, or when Esc is pressed while closeOnEsc is true, with the event. | Type(e: any) => void | - |
| onConfigureClick | Called when the configure button of a built-in tool is clicked, with the event and the option. | Type(e: React.MouseEvent<HTMLButtonElement>, option: MCPReactOption) => void | - |
| onEditClick | Called when the edit button of a custom tool is clicked, with the event and the option. | Type(e: React.MouseEvent<HTMLButtonElement>, option: MCPReactOption) => void | - |
| onSearch | Called on search, with the input value and whether the custom list is searched. | Type(inputValue: string, custom: boolean) => void | - |
| onStatusChange | Called when a tool is enabled or disabled, with the whole updated list and whether it is the custom list; the component does not modify the list, so write the new list back to options or customOptions. | Type(options: MCPReactOption[], custom: boolean) => void | - |
| options | Built-in MCP tools; each item needs a unique value. | MCPReactOption[] | - |
| placeholder | Placeholder of the search input, the locale text by default. | string | - |
| ref | Reference to the root element (.semi-sidebar-container); null after it is hidden and its leave animation has ended. | TypeReact.Ref<HTMLDivElement> | - |
| renderHeader | Renders the whole header; the built-in header is used when it returns no content. | Type() => ReactNode | - |
| renderItem | Renders a whole tool row, called with { option, custom }. | Type(props: { option: MCPReactOption; custom: boolean }) => ReactNode | - |
| resizable | Whether the width can be resized by dragging, true by default; minWidth, maxWidth and defaultSize apply only when true. | boolean | - |
| showClose | Whether the header shows the close button, true by default. | boolean | - |
| style | Inline style of the root element. | CSSProperties | - |
| title | Title in the header, the locale's MCP configure text by default. | ReactNode | - |
| visible | Whether the container is shown. | boolean | - |
The class name (className) and other native attributes land on the root element .semi-sidebar-container.
MCPReactOption
| Property | Description | Type | Default |
|---|---|---|---|
| active | Whether this MCP is active | boolean | false |
| configure | Whether to show configuration related operation/indicator | boolean | false |
| desc | Description content | ReactNode | - |
| disabled | Whether this MCP is disabled. When true, users cannot toggle its active state | boolean | false |
| icon | Icon element | ReactNode | - |
| label | Label text | string | - |
| value | Value, required. Identifies the option in onStatusChange and is used as the item key, so it must be unique in a list | string | - |
Annotation
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded groups, one or several. | string | string[] | - |
| afterVisibleChange | Called after a visibility change has completed, with whether the container is visible; with motion it runs when the animation ends. | Type(isVisible: boolean) => void | - |
| children | Has no effect; the content is the reference list. | React.ReactNode | - |
| closeOnEsc | Whether pressing Esc calls onCancel, false by default. | boolean | - |
| containerRef | Receives the root element (.semi-sidebar-container), as ref does. | TypeReact.RefObject<HTMLDivElement> | - |
| defaultSize | Initial size (width and height); applies only when resizable is true. | { width?: number | string; height?: number | string } | - |
| info | Groups of references; each has a header, a key and its annotations. | AnnotationInfo[] | - |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | - |
| minWidth | Minimum width when resizing; applies only when resizable is true, 150 by default. | string | number | - |
| motion | Whether showing and hiding use the expand animation, true by default. | boolean | - |
| onCancel | Called when the close button is clicked, or when Esc is pressed while closeOnEsc is true, with the event. | Type(e: any) => void | - |
| onChange | Called when the expanded groups change, with the expanded keys. | Type(key: string | string[]) => void | - |
| onClick | Called when a reference is clicked, with the event and the item. | Type(e: React.MouseEvent, item: AnnotationItem) => void | - |
| ref | Reference to the root element (.semi-sidebar-container); null after it is hidden and its leave animation has ended. | TypeReact.Ref<HTMLDivElement> | - |
| renderHeader | Renders the whole header; the built-in header is used when it returns no content. | Type() => ReactNode | - |
| renderItem | Renders a reference item, called with the item. | Type(annotation: AnnotationItem) => ReactNode | - |
| resizable | Whether the width can be resized by dragging, true by default; minWidth, maxWidth and defaultSize apply only when true. | boolean | - |
| showClose | Whether the header shows the close button, true by default. | boolean | - |
| style | Inline style of the root element. | CSSProperties | - |
| title | Title in the header, the locale's references text by default. | ReactNode | - |
| visible | Whether the container is shown. | boolean | - |
The class name (className) and other native attributes land on the root element .semi-sidebar-container.
AnnotationContent
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded groups, one or several. | string | string[] | - |
| className | Class name of the Collapse root element. | string | - |
| info | Groups of references; each has a header, a key and its annotations. | AnnotationInfo[] | [] |
| onChange | Called when the expanded groups change, with the expanded keys. | Type(key: string | string[]) => void | - |
| onClick | Called when a reference is clicked, with the event and the item. | Type(e: React.MouseEvent, item: AnnotationItem) => void | - |
| renderItem | Renders a reference item, called with the item. | Type(annotation: AnnotationItem) => ReactNode | - |
| style | Inline style of the Collapse root element. | React.CSSProperties | - |
Other native attributes land on the Collapse root element.
AnnotationItem
| Property | Description | Type | Default |
|---|---|---|---|
| detail | Extra detail text such as video description or text note | string | - |
| duration | Duration, usually used for videos, in seconds | number | - |
| img | Image url, such as video cover or illustration | string | - |
| logo | Logo url of the site/platform to which the content belongs | string | - |
| onClick | Callback when item is clicked, returns event and current reference item | (event: MouseEvent, item: AnnotationItem) => void | - |
| order | Order/index number | number | - |
| siteName | Name of the site/platform where the content belongs | string | - |
| title | Title | string | - |
| type | Content type | 'video' | 'text' | - |
| url | Resource url. Clicking the reference will open this link | string | - |
Sidebar
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Key of the selected option in the main view. | string | - |
| afterVisibleChange | Called after a visibility change has completed, with whether the sidebar is visible; with motion it runs when the animation ends. | Type(isVisible: boolean) => void | - |
| children | Has no effect; the content is the main or detail view. | React.ReactNode | - |
| closeOnEsc | Whether pressing Esc calls onCancel, false by default. | boolean | - |
| containerRef | Has no effect; use ref to get the container element. | TypeReact.RefObject<HTMLDivElement> | - |
| defaultSize | Initial size (width and height); applies only when resizable is true. | { width?: number | string; height?: number | string } | - |
| detailContent | The 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, imgUploadProps and onContentChange have no effect, as fileEditable, imgUploadProps and onFileContentChange decide them. | DetailContent | - |
| fileEditable | Whether the rich text in file mode is editable. | boolean | true |
| imgUploadProps | Image upload options of file mode, read when the editor is created; later changes have no effect. The toolbar shows the image button only when action or customRequest is set. | ImageUploadNodeOptions | - |
| maxWidth | Maximum width when resizing; applies only when resizable is true. | string | number | - |
| minWidth | Minimum width when resizing; applies only when resizable is true, 150 by default. | string | number | - |
| mode | Display mode: main is the main view, code and file use the built-in details, and any other string is rendered by renderDetailContent. | string | "main" |
| motion | Whether showing and hiding use the expand animation, true by default. | boolean | - |
| onActiveOptionChange | Called when an option button is clicked, with the event and the option key; write the key back to activeKey yourself. | Type(e: React.MouseEvent, activeKey: string) => void | - |
| onBackWard | Called when the back button of the detail header is clicked, with the event and main; set mode back to main yourself. The return value is ignored. | Type(e: React.MouseEvent, mode: string) => void | Promise<any> | - |
| onCancel | Called when the close button is clicked, or when Esc is pressed while closeOnEsc is true, with the event. | Type(e: any) => void | - |
| onDetailContentCopy | Called after the copy button of the detail header is clicked, once the clipboard write has settled, with the event, the copied content and the result (false when the write is rejected). | Type(e: React.MouseEvent, content: string, res: boolean) => void | - |
| onFileContentChange | Called after the rich text is edited in file mode, with the HTML string. | Type(content: string) => void | - |
| options | Option buttons at the top of the main view, each with a name, a key and an optional icon. | Option[] | - |
| ref | Reference to the root element (.semi-sidebar-container); null after it is hidden and its leave animation has ended. | TypeReact.Ref<HTMLDivElement> | - |
| renderDetailContent | Renders the detail content, called with the mode; when it returns no content, code and file modes fall back to the built-in detail. | Type(mode: string) => ReactNode | - |
| renderDetailHeader | Renders the detail header, called with the mode and detailContent; the built-in header is used when it returns no content. | Type(mode: string, detailContent?: DetailContent) => ReactNode | - |
| renderHeader | Has no effect; use title for the main view and renderDetailHeader for detail views. | Type() => ReactNode | - |
| renderMainContent | Renders the main view, called with the selected activeKey. | Type(activeKey: string) => ReactNode | - |
| renderOptionItem | Renders an option button; the second argument, onChange, selects the option when called with the event and the option key. | Type(option: Option, onChange: (e: React.MouseEvent, activeKey: string) => void) => ReactNode | - |
| resizable | Whether the width can be resized by dragging, true by default; minWidth, maxWidth and defaultSize apply only when true. | boolean | - |
| showClose | Whether the header shows the close button, true by default. | boolean | - |
| style | Inline style of the root element. | CSSProperties | - |
| title | Title of the main view; detail views use the detail header. | ReactNode | - |
| visible | Whether the sidebar is shown. | boolean | - |
The class name (className) and other native attributes land on the root element .semi-sidebar-container.
Option
| Property | Description | Type | Default |
|---|---|---|---|
| icon | Option icon | ReactNode | - |
| key | Unique key of the option | string | - |
| name | Option name | ReactNode | - |
CodeContent
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded code panels, one or several. | string | string[] | - |
| className | Class name of the Collapse root element. | string | - |
| codes | The code entries, each with the CodeItem props and a key identifying its panel. | CodeItemProps[] | [] |
| onChange | Called when the expanded panels change, with the expanded keys. | Type(activeKey: string | string[]) => void | - |
| onExpand | Called when the expand button in a panel header is clicked, with the event, the code entry and the mode code; the button is shown only when this is set. | Type(e: React.MouseEvent, code: CodeItemProps, mode: string) => void | - |
| style | Inline style of the Collapse root element. | React.CSSProperties | - |
Other native attributes land on the Collapse root element.
CodeItem
Props
| Property | Description | Type | Default |
|---|---|---|---|
| codeHighlightProps | Props of CodeHighlight, spread after code and language. | CodeHighlightProps | - |
| content | Code or text content. | string | - |
| isJson | Whether the content is JSON; when true, JsonViewer displays it. | boolean | - |
| jsonViewerProps | Props of JsonViewer, spread after the defaults for value, height, width and so on. | TypePartial<JsonViewerProps> | {} |
| key | Identifies the panel for the activeKey of CodeContent, and decides when a Sidebar detail remounts. | string | - |
| language | Language of the code (such as js, ts or css), same as language of CodeHighlight. | string | - |
| name | Name, shown in the panel header and in the Sidebar detail header. | string | - |
Other native attributes land on the .semi-sidebar-code-content root element.
FileContent
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded file panels, one or several. | string | string[] | - |
| className | Class name of the Collapse root element. | string | - |
| files | The file entries, rendered read-only: each is the FileItem props plus a key identifying its panel; its className, style and other attributes are passed to the preview. | FileItemProps[] | [] |
| onChange | Called when the expanded panels change, with the expanded keys. | Type(activeKey: string | string[]) => void | - |
| onExpand | Called when the expand button in a panel header is clicked, with the event, the file entry and the mode file; the button is shown only when this is set. | Type(e: React.MouseEvent, file: FileItemProps, mode: string) => void | - |
| style | Inline style of the Collapse root element. | React.CSSProperties | - |
Other native attributes land on the Collapse root element.
FileItem
Props
| Property | Description | Type | Default |
|---|---|---|---|
| className | Class name of the root element. | string | - |
| content | Rich text as an HTML string. A change after mount is synced to the editor, and the editor is not reset when the value equals its current content; the sync does not call onContentChange. | string | - |
| editable | Whether the content is editable; a change after mount is synced to the editor. | boolean | true |
| extensions | tiptap extensions (Extension, Node or Mark) appended to the built-in ones, read when the editor is created; later changes have no effect. | Extensions | [] |
| imgUploadProps | Image upload options, read when the editor is created; later changes have no effect. The toolbar shows the image button only when action or customRequest is set; getUploadImageSrc(response) returns the image address from the upload response, and when it is not provided, a string response is used as the address and otherwise response.src is used. | ImageUploadNodeOptions | - |
| key | Identifies the panel for the activeKey of FileContent, and decides when a Sidebar detail remounts. | string | - |
| name | Name, shown in the panel header and the Sidebar detail header, and used as the aria-label of the editing area. | string | - |
| onContentChange | Called after an edit, with the content as HTML. | Type(content: string) => void | - |
| style | Inline style of the root element. | React.CSSProperties | - |
Other native attributes land on the root element.
