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-solid';
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 title, which can be any content; userenderHeaderto customize the whole headermotionsets whether to enable the expand animationresizablesets whether the width is resizable. Whentrue, you can useminWidthandmaxWidthto control min and max width
Code
import { type JSX, createSignal } from 'solid-js';
import { Sidebar } from '@fibrous/semi-ai-solid';
import { Button, Switch } from '@fibrous/semi-ui-solid';
const { Container } = Sidebar;
const containerStyle: JSX.CSSProperties = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
'border-radius': '8px',
overflow: 'hidden',
'box-sizing': 'border-box',
};
export default function SidebarDemo() {
const [visible, setVisible] = createSignal(true);
const [motion, setMotion] = createSignal(true);
const [resizable, setResizable] = createSignal(true);
const toggleVisible = () => setVisible((current) => !current);
return (
<div style={containerStyle}>
<div style={{ 'flex-grow': 1, 'flex-shrink': 1, padding: '20px' }}>
<div>
<Button aria-pressed={visible()} onClick={toggleVisible}>
显示容器
</Button>
<div style={{ display: 'flex', 'align-items': 'center', 'margin-top': '10px' }}>
<span id="sidebar-container-motion">是否有动画</span> <Switch aria-labelledby="sidebar-container-motion" checked={motion()} onChange={setMotion} />
</div>
<div style={{ display: 'flex', 'align-items': 'center', 'margin-top': '10px' }}>
<span id="sidebar-container-resizable">是否可伸缩</span> <Switch aria-labelledby="sidebar-container-resizable" checked={resizable()} onChange={setResizable} />
</div>
</div>
</div>
<Container motion={motion()} resizable={resizable()} minWidth={250} maxWidth="60%" visible={visible()} title="基础容器示例" style={resizable() ? {} : { width: '200px' }} onCancel={toggleVisible} />
</div>
);
}MCP Configuration
Use MCPConfigure to display, enable/disable, configure and search MCP tools.
- Use
optionsandcustomOptionsto set the built-in and custom MCP tools - Use
visibleto control show and hide, andonCancelto listen to user close behavior - Use
onStatusChangeto handle enabling/disabling of MCP tools; the component never changes the lists you pass, so write the callback argument back tooptionsorcustomOptions - 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 - Use
renderIconandrenderDescfor the icon and description of an item, andrenderItemto replace the whole row; they are called with{ option, custom }
For other APIs of MCPConfigure, see MCPConfigure.
The type of MCP tool item is as follows:
interface MCPConfigureOption {
icon?: string; // image URL; use renderIcon for other content
label?: string;
value: string; // required, identifies the tool and must be unique
desc?: string; // plain text; use renderDesc for other content
active?: boolean;
disabled?: boolean;
configure?: boolean; // whether to show configure button
}
Usage example:
Code
import { type Component, type JSX, Show, createSignal } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { MCPConfigure, type MCPConfigureOption as MCPOption } from '@fibrous/semi-ai-solid';
import { IconFigma, IconSemiLogo } from '@fibrous/semi-icons-solid';
import { Button, Form, FormInput, FormTextArea, Modal, type FormHandle } from '@fibrous/semi-ui-solid';
interface McpFormValues {
name: string;
src: string;
desc: string;
}
// icon only takes an image URL, so the built-in options get their icons from renderIcon
const builtinIcons: Record<string, Component> = {
'Semi mcp': IconSemiLogo,
figma: IconFigma,
};
const imageStyle: JSX.CSSProperties = { width: '100%', height: '100%' };
const defaultOptions: MCPOption[] = [
{
value: 'Semi mcp',
label: 'Semi',
configure: true,
desc: '支持 Semi 的文档、源码搜索,辅助开发',
},
{
value: 'figma',
label: 'Figma',
desc: 'Figma MCP Server 连接Figma与AI开发工具的功能。它通过标准化的模型上下文协MCP),将组件、变量等设计数据和上下文暴露给AI,从而实现从设计稿到代码的智能生成,显著提升开发效率。',
},
];
let index = 1;
const containerStyle: JSX.CSSProperties = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
'border-radius': '8px',
overflow: 'hidden',
'box-sizing': 'border-box',
};
export default function SidebarDemo() {
const [visible, setVisible] = createSignal(true);
const [options, setOptions] = createSignal(defaultOptions);
const [mVisible, setMVisible] = createSignal(false);
const [customOptions, setCustomOptions] = createSignal<MCPOption[]>([]);
let form: FormHandle<McpFormValues> | undefined;
const toggleVisible = () => setVisible((current) => !current);
const handleOk = () => {
form?.formApi
.validate()
.then((values) => {
setCustomOptions((current) => [
...current,
{
label: values.name,
icon: values.src,
value: `mcp-${index++}`,
desc: values.desc,
},
]);
setMVisible(false);
})
.catch((errors) => {
console.log('errors', errors);
});
};
const onStatusChange = (changed: MCPOption[], custom: boolean) => {
if (custom) {
setCustomOptions(changed);
} else {
setOptions(changed);
}
};
return (
<div style={containerStyle}>
<div style={{ 'flex-grow': 1, 'flex-shrink': 1, padding: '20px' }}>
<Button aria-pressed={visible()} onClick={toggleVisible}>
MCP 配置
</Button>
</div>
<MCPConfigure
style={{ width: '500px' }}
resizable={false}
visible={visible()}
onCancel={toggleVisible}
options={options()}
customOptions={customOptions()}
onStatusChange={onStatusChange}
onAddClick={() => setMVisible(true)}
onConfigureClick={(_e, option) => console.log('configure click', option)}
onEditClick={(_e, option) => console.log('edit click', option)}
renderIcon={({ option }) => (
<Show when={option.icon} fallback={<Dynamic component={builtinIcons[option.value]} />}>
{(src) => <img alt="" src={src()} style={imageStyle} />}
</Show>
)}
/>
<Modal title="自定义 MCP" visible={mVisible()} onOk={handleOk} onCancel={() => setMVisible(false)} closeOnEsc>
<Form ref={(node) => (form = node)} layout="vertical" onValueChange={(values) => console.log(values)}>
<FormInput rules={[{ required: true, message: '请输入 MCP 名称' }]} field="name" label="MCP 名称" style={{ width: '100%' }} />
<FormInput
initValue="/assets/placeholder/avatar-a.svg"
rules={[
{ required: true, message: '请输入 MCP 图标 URL' },
{
validator: (_rule: unknown, value: string) => {
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%' }}
/>
<FormTextArea rules={[{ required: true, message: '请输入 MCP 介绍' }]} field="desc" label="MCP 介绍" style={{ width: '100%' }} />
</Form>
</Modal>
</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 listonClickis called when a reference is clicked, with the event and the item- Use
renderInfoHeaderfor a group header andrenderItemto replace an item;renderHeaderrenders the header of the whole container
Code
import { type JSX, createSignal } from 'solid-js';
import { Annotation, type AnnotationInfo, type AnnotationItem } from '@fibrous/semi-ai-solid';
import { Button } from '@fibrous/semi-ui-solid';
const containerStyle: JSX.CSSProperties = {
display: 'flex',
height: '500px',
border: '1px solid var(--semi-color-border)',
'border-radius': '8px',
overflow: 'hidden',
'box-sizing': 'border-box',
};
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: '/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] = createSignal(true);
const [activeKey, setActiveKey] = createSignal<string | string[]>('1');
const toggleVisible = () => setVisible((current) => !current);
const onChange = (key: string | string[]) => {
console.log('onChange', key);
setActiveKey(key);
};
const onClick = (e: MouseEvent, item: AnnotationItem) => {
console.log('onClick', e, item);
};
return (
<div style={containerStyle}>
<div style={{ 'flex-grow': 1, 'flex-shrink': 1, padding: '20px' }}>
<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
jsonViewerProps and codeHighlightProps are the props of the Solid JsonViewer and CodeHighlight. They are spread after the built-in defaults, so value, width, height and the like override those defaults, and class and style are accepted too.
Code
import { createSignal } from 'solid-js';
import { Sidebar } from '@fibrous/semi-ai-solid';
import { Radio, RadioGroup } from '@fibrous/semi-ui-solid';
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] = createSignal('json');
return (
<>
<RadioGroup type="button" buttonSize="middle" value={type()} onChange={(e) => setType(e.target.value)} style={{ 'margin-bottom': '10px' }}>
<Radio value="json">JSON</Radio>
<Radio value="css">CSS</Radio>
</RadioGroup>
<div style={{ height: '200px', 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; the button is shown only when it is set
Code
import { createSignal } from 'solid-js';
import { Sidebar } from '@fibrous/semi-ai-solid';
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] = createSignal<string | string[]>('code1');
return (
<div class="semi-sidebar-main">
<CodeContent style={{ width: '600px' }} activeKey={activeKey()} codes={defaultCodes} onChange={setActiveKey} />
</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 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 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; theoncallbacks of Upload (such asonSuccess) can be passed here too. The toolbar shows the image button only whenactionorcustomRequestis setextensionsandimgUploadPropsare read only when the editor is created; remount the component to apply new values, for example by wrapping it in<Show when={version} keyed>onContentChangeis called after an edit, with the content as HTML
Code
import { createSignal } from 'solid-js';
import { Sidebar, type ImageUploadNodeOptions } from '@fibrous/semi-ai-solid';
import { Button } from '@fibrous/semi-ui-solid';
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] = createSignal(true);
return (
<>
<Button aria-pressed={editable()} onClick={() => setEditable((current) => !current)}>
可编辑
</Button>
<br />
<br />
<FileItem name="Semi Design 介绍" content={defaultFileContent} editable={editable()} style={{ border: '1px solid var(--semi-color-border)', padding: '12px' }} 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; the button is shown only when it is set
Code
import { createSignal } from 'solid-js';
import { Sidebar } from '@fibrous/semi-ai-solid';
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] = createSignal<string | string[]>('file1');
return (
<div class="semi-sidebar-main">
<FileContent style={{ width: '600px' }} activeKey={activeKey()} files={defaultFiles} onChange={setActiveKey} />
</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 the top button group through options (each item is { name, key }); activeKey together with onActiveOptionChange manages the selected item. Use renderOptionIcon for the button icon, or renderOptionItem to replace the whole button, whose second parameter onChange selects the item.
For content rendering in the main view, pass a render function via renderMainContent, called with the selected activeKey. You can use AnnotationContent in Annotation to render references, FileContent in Sidebar to render rich text, and CodeContent to render code. The render function runs again for every signal it reads, so read state signals such as the expanded panels only in the props you pass to the child components, which keeps the content from being rebuilt as a whole.
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 renderDetailContent, and customize the detail header through renderDetailHeader; when they return empty content, both fall back to the built-in ones. Clicking the back button of the detail header calls onBackWard.
Code
import { type Component, type JSX, Match, Switch, createSignal } from 'solid-js';
import { Dynamic } from 'solid-js/web';
import { Annotation, Sidebar, type AnnotationInfo, type ImageUploadNodeOptions, type SideBarDetailContent, type SideBarOption } from '@fibrous/semi-ai-solid';
import { IconBriefStroked, IconCodeStroked, IconModalStroked, IconSearch } from '@fibrous/semi-icons-solid';
const { FileContent, CodeContent } = Sidebar;
const { AnnotationContent } = Annotation;
const containerStyle: JSX.CSSProperties = {
display: 'flex',
height: '800px',
border: '1px solid var(--semi-color-border)',
'border-radius': '8px',
overflow: 'hidden',
'box-sizing': 'border-box',
};
const optionList: SideBarOption[] = [
{ 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 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: '/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] = createSignal('main');
const [activeKey, setActiveKey] = createSignal('codePreview');
const [activeCodeKey, setActiveCodeKey] = createSignal<string | string[]>('code1');
const [activeFileKey, setActiveFileKey] = createSignal<string | string[]>('file1');
const [activeReferKey, setActiveReferKey] = createSignal<string | string[]>('1');
const [currentDetail, setCurrentDetail] = createSignal<SideBarDetailContent>();
const onExpand = (_e: MouseEvent, content: SideBarDetailContent, mode: string) => {
setMode(mode);
setCurrentDetail(content);
};
return (
<div style={containerStyle}>
<div style={{ 'flex-grow': 1, 'flex-shrink': 1, padding: '20px' }}>工作区占位</div>
<Sidebar
showClose={false}
visible
motion={false}
title="Agent 的工作空间"
mode={mode()}
defaultSize={{ width: '60%' }}
onActiveOptionChange={(_e, key) => setActiveKey(key)}
activeKey={activeKey()}
options={optionList}
renderOptionIcon={(option) => <Dynamic component={optionIcons[option.key]} />}
onBackWard={(_e, next) => {
setMode(next);
}}
renderMainContent={(key) => (
<Switch>
<Match when={key === 'searchResult'}>
<AnnotationContent activeKey={activeReferKey()} info={defaultInfoList} onChange={setActiveReferKey} />
</Match>
<Match when={key === 'filePreview'}>
<FileContent activeKey={activeFileKey()} files={defaultFiles} onExpand={onExpand} onChange={setActiveFileKey} />
</Match>
<Match when={key === 'codePreview'}>
<CodeContent activeKey={activeCodeKey()} codes={defaultCodes} onExpand={onExpand} onChange={setActiveCodeKey} />
</Match>
<Match when={key === 'network'}>
<img alt="network" src="/assets/root-web-sites/test.jpg" style={{ width: '100%' }} />
</Match>
</Switch>
)}
detailContent={currentDetail()}
imgUploadProps={imgUploadProps}
/>
</div>
);
}API Reference
The class, style, ref and other undeclared attributes (such as aria-label, id and data-*) 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. For CodeContent, FileContent and AnnotationContent they land on their own root element (the collapse), and for CodeItem and FileItem on their own root div.
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. | JSX.Element | - |
| closeOnEsc | Whether pressing Esc calls onCancel. | boolean | - |
| containerRef | Receives the .semi-sidebar-container element, as ref does. | TypeRef<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. | string | number | 150 |
| motion | Whether showing and hiding use the expand animation. | boolean | true |
| onCancel | Called when the close button is clicked, or when Esc is pressed while closeOnEsc is true. | Type(e: MouseEvent | KeyboardEvent) => void | - |
| renderHeader | Renders the whole header; the built-in header is used when it returns no content. | Type() => JSX.Element | - |
| resizable | Whether the width can be resized by dragging; minWidth, maxWidth and defaultSize apply only when true. | boolean | true |
| showClose | Whether the header shows the close button. | boolean | true |
| style | Inline style of the container element, a style object or a string. | JSX.CSSProperties | string | - |
| title | Title in the header; any content. | JSX.Element | - |
| visible | Whether the container is shown. | boolean | - |
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. | JSX.Element | - |
| closeOnEsc | Whether pressing Esc calls onCancel. | boolean | - |
| containerRef | Receives the .semi-sidebar-container element, as ref does. | TypeRef<HTMLDivElement> | - |
| customOptions | Custom MCP tools, listed on the custom tab. | MCPSolidOption[] | - |
| 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: MCPSolidOption) => 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. | Type(e: MouseEvent) => void | - |
| onCancel | Called when the close button is clicked, or when Esc is pressed while closeOnEsc is true. | Type(e: MouseEvent | KeyboardEvent) => void | - |
| onConfigureClick | Called when the configure button of a built-in tool is clicked, with the event and the option. | Type(e: MouseEvent, option: MCPSolidOption) => void | - |
| onEditClick | Called when the edit button of a custom tool is clicked, with the event and the option. | Type(e: MouseEvent, option: MCPSolidOption) => 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; write the new list back to options or customOptions yourself. | Type(options: MCPSolidOption[], custom: boolean) => void | - |
| options | Built-in MCP tools; each item needs a unique value. | MCPSolidOption[] | - |
| placeholder | Placeholder of the search input, the locale text by default. | string | - |
| renderDesc | Renders the description of a tool row, called with { option, custom }; without it the option's desc text is shown. | Type(props: MCPRenderItemProps) => JSX.Element | - |
| renderHeader | Renders the whole header; the built-in header is used when it returns no content. | Type() => JSX.Element | - |
| renderIcon | Renders the icon of a tool row, called with { option, custom }; without it the option's icon is rendered as an image URL. | Type(props: MCPRenderItemProps) => JSX.Element | - |
| renderItem | Renders a whole tool row, called with { option, custom }. | Type(props: MCPRenderItemProps) => JSX.Element | - |
| 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 container element, a style object or a string. | JSX.CSSProperties | string | - |
| title | Title in the header, the locale's MCP configure text by default. | JSX.Element | - |
| visible | Whether the container is shown. | boolean | - |
MCPConfigureOption
| Property | Description | Type | Default |
|---|---|---|---|
| active | Whether the tool is active | boolean | false |
| configure | Whether to show the configure button | boolean | false |
| desc | Description text, matched by the built-in filter; use renderDesc for other content | string | - |
| disabled | Whether the tool is disabled; when true, the user cannot change its active state | boolean | false |
| icon | Image URL of the icon; use renderIcon for other content | string | - |
| label | Label text | string | - |
| value | Required. Identifies the tool in onStatusChange and keys its row, so it must be unique within the same 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. | JSX.Element | - |
| closeOnEsc | Whether pressing Esc calls onCancel. | boolean | - |
| containerRef | Receives the .semi-sidebar-container element, as ref does. | TypeRef<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. | Type(e: MouseEvent | KeyboardEvent) => 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: MouseEvent, item: AnnotationItem) => void | - |
| renderHeader | Renders the whole header; the built-in header is used when it returns no content. | Type() => JSX.Element | - |
| renderInfoHeader | Renders a group header after its icon, called with the group; without it the group's header text is shown. AnnotationContent's renderHeader, renamed beside the container's renderHeader. | ContentProps['renderHeader'] | - |
| renderItem | Renders a reference item, called with the item. | Type(annotation: AnnotationItem) => JSX.Element | - |
| 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 container element, a style object or a string. | JSX.CSSProperties | string | - |
| title | Title in the header, the locale's references text by default. | JSX.Element | - |
| visible | Whether the container is shown. | boolean | - |
AnnotationContent
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded groups, one or several. | string | 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: MouseEvent, item: AnnotationItem) => void | - |
| renderHeader | Renders a group header after its icon, called with the group; without it the group's header text is shown. | Type(info: AnnotationInfo) => JSX.Element | - |
| renderItem | Renders a reference item, called with the item. | Type(annotation: AnnotationItem) => JSX.Element | - |
AnnotationInfo
| Property | Description | Type | Default |
|---|---|---|---|
| annotations | References of the group | AnnotationItem[] | - |
| header | Plain text of the group header; customize it with renderInfoHeader (Annotation) or renderHeader (AnnotationContent) | string | - |
| key | Unique identifier of the group | string | - |
AnnotationItem
| Property | Description | Type | Default |
|---|---|---|---|
| detail | Detail or supplementary text (such as a video summary or a text note) | string | - |
| duration | Duration, usually of a video, in seconds | number | - |
| img | Image URL (such as a video cover or a text illustration) | string | - |
| logo | Logo image URL of the site or platform | string | - |
| onClick | Called when the item is clicked, with the event and the item (without onClick); used instead of the Annotation's | (event: MouseEvent, item: AnnotationItem) => void | - |
| order | Citation number (used for ordering and for the number badge) | number | - |
| siteName | Name of the site or platform | string | - |
| title | Title | string | - |
| type | Content type | 'video' | 'text' | - |
| url | Resource link, opened in a new tab; an item without url renders a link without href that only a pointer can use | 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. | JSX.Element | - |
| closeOnEsc | Whether pressing Esc calls onCancel. | boolean | - |
| containerRef | Has no effect; use ref to get the container element. | TypeRef<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. | 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: 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: MouseEvent, mode: string) => void | Promise<unknown> | - |
| onCancel | Called when the close button is clicked, or when Esc is pressed while closeOnEsc is true. | Type(e: MouseEvent | KeyboardEvent) => 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: 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 and a key; the icons come from renderOptionIcon. | Option[] | - |
| 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) => JSX.Element | - |
| 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) => JSX.Element | - |
| renderHeader | Has no effect; use title for the main view and renderDetailHeader for detail views. | Type() => JSX.Element | - |
| renderMainContent | Renders the main view, called with the selected activeKey. | Type(activeKey: string) => JSX.Element | - |
| renderOptionIcon | Renders the icon of a built-in option button, called with the option. | Type(option: Option) => JSX.Element | - |
| renderOptionItem | Renders an option button; the second argument, onChange, selects the option. | Type(option: Option, onChange: (e: MouseEvent, activeKey: string) => void) => JSX.Element | - |
| 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 container element, a style object or a string. | JSX.CSSProperties | string | - |
| title | Title of the main view; detail views use the detail header. | JSX.Element | - |
| visible | Whether the sidebar is shown. | boolean | - |
SideBarOption
| Property | Description | Type | Default |
|---|---|---|---|
| key | Unique identifier of the option | string | - |
| name | Option name; use renderOptionIcon for the icon | string | - |
CodeContent
Each item of codes is the props of CodeItem plus a key identifying its panel.
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded code panels, one or several. | string | 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 code; the button is shown only when this is set. | Type(e: MouseEvent, code: CodeItemProps, mode: string) => void | - |
CodeItem
Props
| Property | Description | Type | Default |
|---|---|---|---|
| codeHighlightProps | Props of CodeHighlight, spread after code and language. | TypePartial<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, width, height 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 | - |
class, style and native attributes land on the root div.
FileContent
Each item of files is the props of FileItem plus a key identifying its panel. They are rendered read-only, and extensions and imgUploadProps reach their previews.
Props
| Property | Description | Type | Default |
|---|---|---|---|
| activeKey | Keys of the expanded file panels, one or several. | string | string[] | - |
| files | The file entries, rendered read-only: each is the FileItem props plus a key identifying its panel. | 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 file; the button is shown only when this is set. | Type(e: MouseEvent, file: FileItemProps, mode: string) => void | - |
FileItem
Props
| Property | Description | Type | Default |
|---|---|---|---|
| content | Rich text as HTML; a change after mount is synced to the editor without calling onContentChange. | string | - |
| editable | Whether the content is editable; a change after mount is synced to the editor. | boolean | true |
| extensions | tiptap extensions appended to the built-in ones, read when the editor is created. | Extensions | - |
| imgUploadProps | Image upload options, read when the editor is created. | 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 | - |
class, style and native attributes land on the root div.
