Skip to content

Splitter

Create resizable split panes with draggable dividers.

import { Splitter } from 'asterui'

Basic Horizontal Splitter

Drag the divider to resize the panels.

Left Panel

Drag the divider to resize.

Right Panel

Content on the right side.

import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-64 border border-base-300 rounded-lg overflow-hidden">
        <Splitter>
          <Splitter.Panel>
            <div className="p-4 bg-base-200 h-full">
              <h3 className="font-semibold">Left Panel</h3>
              <p className="text-sm text-base-content/70 mt-2">Drag the divider to resize.</p>
            </div>
          </Splitter.Panel>
          <Splitter.Panel>
            <div className="p-4 h-full">
              <h3 className="font-semibold">Right Panel</h3>
              <p className="text-sm text-base-content/70 mt-2">Content on the right side.</p>
            </div>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

Vertical Splitter

Split panels vertically.

Top Panel

Bottom Panel

import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-64 border border-base-300 rounded-lg overflow-hidden">
        <Splitter direction="vertical">
          <Splitter.Panel>
            <div className="p-4 bg-base-200 h-full">
              <h3 className="font-semibold">Top Panel</h3>
            </div>
          </Splitter.Panel>
          <Splitter.Panel>
            <div className="p-4 h-full">
              <h3 className="font-semibold">Bottom Panel</h3>
            </div>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

Controlled Sizes

Control panel sizes programmatically.

30%
70%
import { Splitter, Button, Space } from 'asterui'
import { useState } from 'react'

function App() {
  const [sizes, setSizes] = useState([30, 70]);
  
  return (
      <div>
        <Space className="mb-4">
          <Button size="sm" onClick={() => setSizes([20, 80])}>
            20/80
          </Button>
          <Button size="sm" onClick={() => setSizes([50, 50])}>
            50/50
          </Button>
          <Button size="sm" onClick={() => setSizes([80, 20])}>
            80/20
          </Button>
        </Space>
        <div className="h-48 border border-base-300 rounded-lg overflow-hidden">
          <Splitter sizes={sizes} onSizesChange={setSizes}>
            <Splitter.Panel>
              <div className="p-4 bg-primary/10 h-full">{sizes[0].toFixed(0)}%</div>
            </Splitter.Panel>
            <Splitter.Panel>
              <div className="p-4 bg-secondary/10 h-full">{sizes[1].toFixed(0)}%</div>
            </Splitter.Panel>
          </Splitter>
        </div>
      </div>
    )
}

export default App

Multiple Panels

Split into more than two panels.

Panel 1
Panel 2
Panel 3
import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-48 border border-base-300 rounded-lg overflow-hidden">
        <Splitter defaultSizes={[25, 50, 25]}>
          <Splitter.Panel>
            <div className="p-4 bg-primary/10 h-full">Panel 1</div>
          </Splitter.Panel>
          <Splitter.Panel>
            <div className="p-4 bg-secondary/10 h-full">Panel 2</div>
          </Splitter.Panel>
          <Splitter.Panel>
            <div className="p-4 bg-accent/10 h-full">Panel 3</div>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

With Min/Max Sizes

Constrain panel sizes with min and max values.

Min: 100px, Max: 300px

Min: 150px

import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-48 border border-base-300 rounded-lg overflow-hidden">
        <Splitter>
          <Splitter.Panel minSize={100} maxSize={300}>
            <div className="p-4 bg-warning/10 h-full">
              <p className="text-sm">Min: 100px, Max: 300px</p>
            </div>
          </Splitter.Panel>
          <Splitter.Panel minSize={150}>
            <div className="p-4 bg-info/10 h-full">
              <p className="text-sm">Min: 150px</p>
            </div>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

Nested Splitters

Combine horizontal and vertical splitters.

Sidebar

Main Content

Terminal

import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-72 border border-base-300 rounded-lg overflow-hidden">
        <Splitter defaultSizes={[30, 70]}>
          <Splitter.Panel>
            <div className="p-4 bg-base-200 h-full">
              <h3 className="font-semibold">Sidebar</h3>
            </div>
          </Splitter.Panel>
          <Splitter.Panel>
            <Splitter direction="vertical" defaultSizes={[60, 40]}>
              <Splitter.Panel>
                <div className="p-4 h-full">
                  <h3 className="font-semibold">Main Content</h3>
                </div>
              </Splitter.Panel>
              <Splitter.Panel>
                <div className="p-4 bg-base-200 h-full">
                  <h3 className="font-semibold">Terminal</h3>
                </div>
              </Splitter.Panel>
            </Splitter>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

Custom Gutter Size

Adjust the gutter (divider) size.

Wide gutter (12px)
Easier to grab
import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-48 border border-base-300 rounded-lg overflow-hidden">
        <Splitter gutterSize={12}>
          <Splitter.Panel>
            <div className="p-4 bg-success/10 h-full">Wide gutter (12px)</div>
          </Splitter.Panel>
          <Splitter.Panel>
            <div className="p-4 bg-error/10 h-full">Easier to grab</div>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

IDE-Style Layout

Complex layout similar to an IDE.

import React from 'react'
$ npm run build
import { Splitter, Menu } from 'asterui'

function App() {
  return (
      <div className="h-80 border border-base-300 rounded-lg overflow-hidden">
        <Splitter defaultSizes={[20, 80]}>
          <Splitter.Panel minSize={150}>
            <div className="h-full bg-base-200">
              <div className="p-2 border-b border-base-300 font-semibold text-sm">Explorer</div>
              <Menu>
                <Menu.Item>src/</Menu.Item>
                <Menu.Item>components/</Menu.Item>
                <Menu.Item>App.tsx</Menu.Item>
                <Menu.Item>index.ts</Menu.Item>
              </Menu>
            </div>
          </Splitter.Panel>
          <Splitter.Panel>
            <Splitter direction="vertical" defaultSizes={[70, 30]}>
              <Splitter.Panel>
                <div className="h-full p-4">
                  <div className="font-mono text-sm">
                    <span className="text-purple-500">import</span> React{' '}
                    <span className="text-purple-500">from</span>{' '}
                    <span className="text-green-500">'react'</span>
                  </div>
                </div>
              </Splitter.Panel>
              <Splitter.Panel>
                <div className="h-full bg-base-300 p-2">
                  <div className="text-xs font-mono text-base-content/70">$ npm run build</div>
                </div>
              </Splitter.Panel>
            </Splitter>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

Collapsible Panels

Panels can be collapsed using arrow buttons on the gutter.

Sidebar

Click the arrow to collapse.

Main Content

This panel expands when the sidebar collapses.

import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-64 border border-base-300 rounded-lg overflow-hidden">
        <Splitter defaultSizes={[25, 75]}>
          <Splitter.Panel collapsible minSize={100}>
            <div className="p-4 bg-base-200 h-full">
              <h3 className="font-semibold">Sidebar</h3>
              <p className="text-sm text-base-content/70 mt-2">
                Click the arrow to collapse.
              </p>
            </div>
          </Splitter.Panel>
          <Splitter.Panel>
            <div className="p-4 h-full">
              <h3 className="font-semibold">Main Content</h3>
              <p className="text-sm text-base-content/70 mt-2">
                This panel expands when the sidebar collapses.
              </p>
            </div>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App

Non-Resizable Panel

Disable resizing for specific panels.

Fixed width (30%)

Cannot resize - divider is disabled.

import { Splitter } from 'asterui'

function App() {
  return (
      <div className="h-48 border border-base-300 rounded-lg overflow-hidden">
        <Splitter>
          <Splitter.Panel resizable={false} defaultSize={30}>
            <div className="p-4 bg-base-200 h-full">
              <p className="text-sm">Fixed width (30%)</p>
            </div>
          </Splitter.Panel>
          <Splitter.Panel>
            <div className="p-4 h-full">
              <p className="text-sm">Cannot resize - divider is disabled.</p>
            </div>
          </Splitter.Panel>
        </Splitter>
      </div>
    )
}

export default App
PropertyDescriptionTypeDefault
directionDirection of the splitter'horizontal' | 'vertical''horizontal'
sizesControlled panel sizes as percentagesnumber[]-
defaultSizesDefault panel sizes as percentages (uncontrolled)number[]-
onSizesChangeCallback when sizes change(sizes: number[]) => void-
gutterSizeSize of the draggable gutter in pixelsnumber8
minSizeDefault minimum panel size in pixelsnumber50
classNameAdditional CSS classesstring-
data-testidTest ID for testingstring-
PropertyDescriptionTypeDefault
childrenPanel contentReact.ReactNode-
defaultSizeDefault size percentagenumber-
sizeControlled size percentagenumber-
minSizeMinimum size in pixelsnumber-
maxSizeMaximum size in pixelsnumber-
collapsibleAllow panel to be collapsedbooleanfalse
collapsedControlled collapsed stateboolean-
defaultCollapsedDefault collapsed statebooleanfalse
onCollapseCallback when collapse state changes(collapsed: boolean) => void-
resizableAllow panel to be resizedbooleantrue
classNameAdditional CSS classesstring-
data-testidTest ID for testingstring-
  • Gutter is keyboard accessible with arrow keys
  • ARIA attributes announce current panel sizes
  • Focus indicators visible on gutter
  • Increase gutterSize for easier touch interaction