SplitPane
分隔面板
分隔面板,支持左右或上下分割,可调整大小,支持折叠功能。
快速开始
import { TripleSplitPane } from "@/registry/wuhan/composed/triple-split-pane";
export function Example() {
return (
<TripleSplitPane
left={{
title: "左侧面板",
children: <div>左侧内容</div>,
}}
center={{
title: "中间面板",
children: <div>中间内容</div>,
}}
right={{
title: "右侧面板",
children: <div>右侧内容</div>,
}}
/>
);
}安装
代码演示
三栏分割面板
使用 TripleSplitPane 创建带标题和折叠图标的三栏分割面板,左右面板支持折叠功能。
基础三栏布局
这是左侧面板的内容区域
示例内容 1
示例内容 2
这是中间面板的内容区域,会自动占满剩余空间
示例内容 A
示例内容 B
这是右侧面板的内容区域
示例内容 X
示例内容 Y
收起时保留宽度(右侧面板收起后显示48px宽度)
左侧面板内容
中间面板内容
右侧面板可以收起为48px宽度,仍然显示折叠图标
默认收起状态(左侧面板默认收起)
中间面板内容
右侧面板内容
"use client";
import { TripleSplitPane } from "@/components/composed/split-pane/triple-split-pane";
export function TripleSplitPaneDemo() {
return (
<div className="flex flex-col gap-8">
{/* 基础三栏布局 */}
<div className="space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
基础三栏布局
</h3>
<TripleSplitPane
className="h-[500px] w-full bg-[var(--Container-bg-neutral-light)] p-3"
left={{
title: "左侧面板",
width: "220px",
collapsedWidth: "0px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
这是左侧面板的内容区域
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">示例内容 1</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">示例内容 2</p>
</div>
</div>
),
}}
center={{
title: "中间面板",
minWidth: "280px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
这是中间面板的内容区域,会自动占满剩余空间
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">示例内容 A</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">示例内容 B</p>
</div>
</div>
),
}}
right={{
title: "右侧面板",
width: "220px",
collapsedWidth: "0px",
minWidth: "180px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
这是右侧面板的内容区域
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">示例内容 X</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">示例内容 Y</p>
</div>
</div>
),
}}
/>
</div>
{/* 收起时保留宽度 */}
<div className="space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
收起时保留宽度(右侧面板收起后显示48px宽度)
</h3>
<TripleSplitPane
className="h-[500px] w-full bg-[var(--Container-bg-neutral-light)] gap-[6px] p-3"
left={{
title: "左侧面板",
width: "180px",
collapsedWidth: "0px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
左侧面板内容
</p>
</div>
),
}}
center={{
title: "中间面板",
minWidth: "250px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
中间面板内容
</p>
</div>
),
}}
right={{
title: "右侧面板",
width: "250px",
collapsedWidth: "48px",
minWidth: "180px",
showIconWhenCompact: true,
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
右侧面板可以收起为48px宽度,仍然显示折叠图标
</p>
</div>
),
}}
/>
</div>
{/* 默认收起状态 */}
<div className="space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
默认收起状态(左侧面板默认收起)
</h3>
<TripleSplitPane
className="h-[500px] w-full bg-[var(--Container-bg-neutral-light)] gap-[6px] p-3"
left={{
title: "左侧面板",
width: "200px",
collapsedWidth: "0px",
defaultCollapsed: true,
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
左侧面板默认收起
</p>
</div>
),
}}
center={{
title: "中间面板",
minWidth: "280px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
中间面板内容
</p>
</div>
),
}}
right={{
title: "右侧面板",
width: "220px",
collapsedWidth: "48px",
minWidth: "180px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
右侧面板内容
</p>
</div>
),
}}
/>
</div>
</div>
);
}
左侧展开按钮 Popover
当左侧面板收起时,中间面板会显示展开按钮。可以为这个展开按钮添加 Popover,在鼠标悬浮时显示快捷导航或其他内容。
左侧展开按钮 Popover 功能
当左侧面板收起时,鼠标悬浮在中间面板的展开按钮上会显示 Popover
这是中间面板的主内容区域
主要内容 A
主要内容 B
右侧面板内容
属性面板
开发者模式:alwaysOpen
设置 alwaysOpen: true 后,Popover 将始终显示,方便开发时调试样式
中间面板内容
右侧面板内容
"use client";
import { TripleSplitPane } from "@/components/composed/split-pane/triple-split-pane";
export function SplitPanePopoverDemo() {
return (
<div className="space-y-8">
{/* 基础 Popover 示例 */}
<div className="space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
左侧展开按钮 Popover 功能
</h3>
<p className="text-sm text-[var(--Text-text-secondary)]">
当左侧面板收起时,鼠标悬浮在中间面板的展开按钮上会显示 Popover
</p>
<TripleSplitPane
className="h-[500px] w-full bg-[var(--Container-bg-neutral-light)] gap-[6px] p-3"
left={{
title: "左侧面板",
width: "220px",
collapsedWidth: "0px",
defaultCollapsed: true,
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
左侧面板内容(默认收起)
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">导航菜单</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">文件树</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">项目结构</p>
</div>
</div>
),
}}
center={{
title: "主内容区",
minWidth: "280px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
这是中间面板的主内容区域
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">主要内容 A</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">主要内容 B</p>
</div>
</div>
),
}}
right={{
title: "右侧面板",
width: "220px",
collapsedWidth: "0px",
minWidth: "180px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
右侧面板内容
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">属性面板</p>
</div>
</div>
),
}}
leftPopover={{
enabled: true,
width: "240px",
height: "300px",
content: (
<div className="p-4 space-y-3">
<h4 className="text-sm font-medium text-[var(--Text-text-primary)]">
快速导航
</h4>
<div className="space-y-2">
<div className="p-2 hover:bg-[var(--Container-bg-neutral-light-hover)] rounded cursor-pointer transition-colors">
<p className="text-xs text-[var(--Text-text-secondary)]">
📁 项目文件
</p>
</div>
<div className="p-2 hover:bg-[var(--Container-bg-neutral-light-hover)] rounded cursor-pointer transition-colors">
<p className="text-xs text-[var(--Text-text-secondary)]">
🔍 搜索
</p>
</div>
<div className="p-2 hover:bg-[var(--Container-bg-neutral-light-hover)] rounded cursor-pointer transition-colors">
<p className="text-xs text-[var(--Text-text-secondary)]">
⚙️ 设置
</p>
</div>
<div className="p-2 hover:bg-[var(--Container-bg-neutral-light-hover)] rounded cursor-pointer transition-colors">
<p className="text-xs text-[var(--Text-text-secondary)]">
📊 数据统计
</p>
</div>
<div className="p-2 hover:bg-[var(--Container-bg-neutral-light-hover)] rounded cursor-pointer transition-colors">
<p className="text-xs text-[var(--Text-text-secondary)]">
🔔 通知中心
</p>
</div>
</div>
</div>
),
}}
/>
</div>
{/* alwaysOpen 开发者模式示例 */}
<div className="space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
开发者模式:alwaysOpen
</h3>
<p className="text-sm text-[var(--Text-text-secondary)]">
设置{" "}
<code className="text-xs bg-[var(--Container-bg-neutral)] px-1 py-0.5 rounded">
alwaysOpen: true
</code>{" "}
后,Popover 将始终显示,方便开发时调试样式
</p>
<TripleSplitPane
className="h-[400px] w-full bg-[var(--Container-bg-neutral-light)] gap-[6px] p-3"
left={{
title: "左侧面板",
width: "220px",
collapsedWidth: "0px",
defaultCollapsed: true,
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
左侧面板内容
</p>
</div>
),
}}
center={{
title: "主内容区",
minWidth: "280px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
中间面板内容
</p>
</div>
),
}}
right={{
title: "右侦面板",
width: "220px",
collapsedWidth: "0px",
minWidth: "180px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
右侧面板内容
</p>
</div>
),
}}
leftPopover={{
enabled: true,
alwaysOpen: true,
width: "200px",
height: "250px",
content: (
<div className="p-4 space-y-3">
<h4 className="text-sm font-medium text-[var(--Text-text-primary)]">
调试模式
</h4>
<p className="text-xs text-[var(--Text-text-secondary)]">
这个 Popover 将始终显示,方便开发时调试样式
</p>
<div className="space-y-2">
<div className="p-2 bg-[var(--Container-bg-neutral-light-hover)] rounded">
<p className="text-xs text-[var(--Text-text-secondary)]">
调试项 1
</p>
</div>
<div className="p-2 bg-[var(--Container-bg-neutral-light-hover)] rounded">
<p className="text-xs text-[var(--Text-text-secondary)]">
调试项 2
</p>
</div>
</div>
</div>
),
}}
/>
</div>
</div>
);
}
自定义面板样式
通过 classNames 属性可以自定义每个面板的容器、头部和内容区域样式。
自定义面板样式
通过 classNames 属性可以自定义每个面板的容器、头部和内容区域样式
这个面板使用了自定义的头部和内容区域样式
导航菜单
文件树
这是中间面板的内容区域,使用了自定义的内边距
主要内容 A
主要内容 B
这个面板的内容区域使用了不同的内边距
属性 1
属性 2
"use client";
import { TripleSplitPane } from "@/components/composed/split-pane/triple-split-pane";
export function SplitPaneClassnamesDemo() {
return (
<div className="space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
自定义面板样式
</h3>
<p className="text-sm text-[var(--Text-text-secondary)]">
通过 classNames 属性可以自定义每个面板的容器、头部和内容区域样式
</p>
<TripleSplitPane
className="h-[500px] w-full bg-[var(--Container-bg-neutral-light)] gap-[6px] p-3"
left={{
title: "左侧面板",
width: "220px",
collapsedWidth: "0px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
这个面板使用了自定义的头部和内容区域样式
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">导航菜单</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">文件树</p>
</div>
</div>
),
classNames: {
container: "shadow-lg",
header: "bg-gradient-to-r from-blue-50 to-indigo-50",
content: "bg-blue-50/30 p-6",
},
}}
center={{
title: "中间面板",
minWidth: "280px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
这是中间面板的内容区域,使用了自定义的内边距
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">主要内容 A</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">主要内容 B</p>
</div>
</div>
),
classNames: {
container: "border-2 border-green-200",
header: "bg-green-50 border-b-2 border-green-200",
content: "p-8",
},
}}
right={{
title: "右侧面板",
width: "220px",
collapsedWidth: "0px",
minWidth: "180px",
children: (
<div className="space-y-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
这个面板的内容区域使用了不同的内边距
</p>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">属性 1</p>
</div>
<div className="p-4 bg-[var(--Container-bg-neutral-light-hover)] rounded-md">
<p className="text-xs">属性 2</p>
</div>
</div>
),
classNames: {
header: "bg-purple-50",
content: "bg-purple-50/20 p-4",
},
}}
/>
</div>
);
}
中间面板头部居中内容
通过 centerHeaderContent 属性可以在中间面板头部添加居中显示的内容,如搜索框、导航标签等。内容会通过绝对定位的方式完美居中,不受左侧展开按钮或标题的影响。
中间面板头部居中内容
通过 centerHeaderContent 属性可以在中间面板头部添加居中显示的内容,如搜索框、导航标签等
项目文件 1
项目文件 2
项目文件 3
这是中间面板的主要内容区域
头部的搜索框会始终保持居中显示,不会受到左侧展开按钮的影响
// 示例代码
function Example() {
return <div>Hello World</div>;
}导航标签居中示例
侧边栏内容
主内容区域,头部导航标签保持居中
详情内容
"use client";
import { TripleSplitPane } from "@/components/composed/split-pane/triple-split-pane";
import { Search, Bell, Settings } from "lucide-react";
export function SplitPaneCenterHeaderDemo() {
return (
<div className="space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
中间面板头部居中内容
</h3>
<p className="text-xs text-[var(--Text-text-secondary)]">
通过 centerHeaderContent
属性可以在中间面板头部添加居中显示的内容,如搜索框、导航标签等
</p>
<TripleSplitPane
className="h-[500px] w-full bg-[var(--Container-bg-neutral-light)] gap-[6px] p-3"
left={{
title: "文件列表",
width: "220px",
collapsedWidth: "0px",
children: (
<div className="space-y-2">
<div className="p-3 bg-[var(--Container-bg-neutral-light-hover)] rounded-md cursor-pointer hover:bg-[var(--Container-bg-neutral-light-active)]">
<p className="text-sm">项目文件 1</p>
</div>
<div className="p-3 bg-[var(--Container-bg-neutral-light-hover)] rounded-md cursor-pointer hover:bg-[var(--Container-bg-neutral-light-active)]">
<p className="text-sm">项目文件 2</p>
</div>
<div className="p-3 bg-[var(--Container-bg-neutral-light-hover)] rounded-md cursor-pointer hover:bg-[var(--Container-bg-neutral-light-active)]">
<p className="text-sm">项目文件 3</p>
</div>
</div>
),
}}
center={{
title: "编辑器",
minWidth: "280px",
/**
* centerHeaderContent - 在中间面板头部添加居中显示的内容
* 该内容会通过绝对定位的方式完美居中,不受左侧展开按钮或标题文本的影响
* 适合放置搜索框、导航标签、状态指示器等需要居中显示的元素
*/
centerHeaderContent: (
<div className="flex items-center gap-2 px-4 py-1 bg-[var(--Container-bg-neutral-light)] rounded-md border border-[var(--Border-border-neutral)]">
<Search className="h-3.5 w-3.5 text-[var(--Text-text-secondary)]" />
<input
type="text"
placeholder="搜索文件..."
className="bg-transparent border-none outline-none text-sm text-[var(--Text-text-primary)] placeholder:text-[var(--Text-text-tertiary)] w-32"
onClick={(e) => e.stopPropagation()}
/>
</div>
),
children: (
<div className="space-y-4">
<div className="p-4 bg-[var(--Container-bg-container)] rounded-md border border-[var(--Border-border-neutral)]">
<p className="text-sm text-[var(--Text-text-secondary)] mb-2">
这是中间面板的主要内容区域
</p>
<p className="text-xs text-[var(--Text-text-tertiary)]">
头部的搜索框会始终保持居中显示,不会受到左侧展开按钮的影响
</p>
</div>
<div className="p-4 bg-[var(--Container-bg-container)] rounded-md border border-[var(--Border-border-neutral)]">
<pre className="text-xs text-[var(--Text-text-secondary)] font-mono">
{`// 示例代码
function Example() {
return <div>Hello World</div>;
}`}
</pre>
</div>
</div>
),
}}
right={{
title: "工具栏",
width: "220px",
collapsedWidth: "0px",
minWidth: "180px",
children: (
<div className="space-y-3">
<div className="flex items-center gap-2 p-2 bg-[var(--Container-bg-neutral-light-hover)] rounded-md cursor-pointer hover:bg-[var(--Container-bg-neutral-light-active)]">
<Bell className="h-4 w-4 text-[var(--Text-text-secondary)]" />
<span className="text-sm">通知</span>
</div>
<div className="flex items-center gap-2 p-2 bg-[var(--Container-bg-neutral-light-hover)] rounded-md cursor-pointer hover:bg-[var(--Container-bg-neutral-light-active)]">
<Settings className="h-4 w-4 text-[var(--Text-text-secondary)]" />
<span className="text-sm">设置</span>
</div>
</div>
),
}}
/>
{/* 示例 2: 导航标签居中 */}
<div className="mt-8 space-y-4">
<h3 className="text-sm font-medium text-[var(--Text-text-primary)]">
导航标签居中示例
</h3>
<TripleSplitPane
className="h-[400px] w-full bg-[var(--Container-bg-neutral-light)] gap-[6px] p-3"
left={{
title: "侧边栏",
width: "220px",
collapsedWidth: "0px",
children: (
<div className="p-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
侧边栏内容
</p>
</div>
),
}}
center={{
title: "主内容",
minWidth: "280px",
/**
* 使用 centerHeaderContent 放置导航标签
* 标签组会在头部居中显示,提供更好的视觉平衡
*/
centerHeaderContent: (
<div className="flex items-center gap-1 bg-[var(--Container-bg-neutral-light)] rounded-lg p-1">
<button className="px-3 py-1 text-xs rounded-md bg-[var(--Container-bg-brand)] text-white">
概览
</button>
<button className="px-3 py-1 text-xs rounded-md hover:bg-[var(--Container-bg-neutral-light-hover)] text-[var(--Text-text-secondary)]">
详情
</button>
<button className="px-3 py-1 text-xs rounded-md hover:bg-[var(--Container-bg-neutral-light-hover)] text-[var(--Text-text-secondary)]">
设置
</button>
</div>
),
children: (
<div className="p-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
主内容区域,头部导航标签保持居中
</p>
</div>
),
}}
right={{
title: "详情",
width: "220px",
collapsedWidth: "0px",
minWidth: "180px",
children: (
<div className="p-4">
<p className="text-sm text-[var(--Text-text-secondary)]">
详情内容
</p>
</div>
),
}}
/>
</div>
</div>
);
}
API
TripleSplitPane
三栏分隔面板,支持左右面板折叠功能。
Props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | 容器自定义类名 |
left | PanelConfig | - | 左侧面板配置 |
center | PanelConfig | - | 中间面板配置 |
right | PanelConfig | - | 右侧面板配置 |
leftPopover | PopoverConfig | - | 左侧展开按钮的 Popover 配置 |
leftExpandButtonDisabled | boolean | false | 是否禁用中间面板的左侧展开按钮(当左侧面板收起时显示的展开按钮) |
PanelConfig
面板配置对象
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | 面板内容 |
title | ReactNode | - | 面板标题 |
centerHeaderContent | ReactNode | - | 头部居中内容(仅中间面板支持),会通过绝对定位居中显示,不受标题和按钮影响 |
width | string | "300px"(左/右)/undefined(中) | 展开时的宽度(像素或百分比字符串) |
minWidth | string | "200px"(左/右)/"400px"(中) | 最小宽度(像素或百分比字符串) |
collapsedWidth | string | "0px" | 折叠后的宽度(像素或百分比字符串),设为 "0px" 表示完全折叠 |
collapsibleIcon | ReactNode | <PanelLeft />(左)/<PanelRight />(右) | 折叠图标 |
showIconWhenCompact | boolean | true | 紧凑模式下是否显示折叠图标 |
defaultCollapsed | boolean | false | 初始是否折叠 |
classNames | object | - | 自定义样式类名(详见下方 ClassNames 说明) |
PanelConfig.classNames
自定义面板样式类名对象
| Prop | Type | Default | Description |
|---|---|---|---|
container | string | - | 面板容器类名 |
header | string | - | 面板头部类名 |
body | string | - | 面板内容区域类名 |
PopoverConfig
Popover 配置对象(用于左侧展开按钮)
| Prop | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | 是否启用 Popover |
content | ReactNode | - | Popover 内容 |
width | string | "240px" | Popover 宽度 |
height | string | "300px" | Popover 高度 |
className | string | - | Popover 自定义类名 |
alwaysOpen | boolean | false | 开发者模式:是否始终显示 Popover(用于调试样式) |
原语组件
TripleSplitPane 组件基于以下原语组件构建:
SplitPaneContainerPrimitive: 分隔面板容器SplitPaneItemPrimitive: 面板项组件,包含标题、折叠按钮和内容区域SplitPaneSeparatorPrimitive: 分隔符组件
如需更灵活的定制,可以直接使用 split-pane-01 中的这些原语组件。