Split Pane

A resizable panel that divides content into two adjustable sections.


1
2
3
4

This component is built on top of Allotment, a lightweight (250 KB unpacked size) and flexible solution for resizable panels. While shadcn/ui uses react-resizable-panel (1.01 MB unpacked size), we opted for Allotment which provides similar core functionality:

  • Proportional layout support
  • Snap-to-zero capability
  • Panel visibility control
  • Minimum and maximum size constraints
  • Nested layout support

We chose Allotment after encountering the "Max Depth Exceeded" error with react-resizable-panels during drag operations in complex layouts (see issue #456).

Automatic Installation

This method is still working on progress, please use manual installation for now.

Manual Installation

Install dependencies

npm install radix-ui lucide-react allotment

Copy the code

components/split-pane/split-pane.tsx
import { Allotment, AllotmentHandle } from 'allotment'
import { Slot } from 'radix-ui'
import * as React from 'react'
import { type SplitPaneStyles, splitPaneStyles } from './split-pane.css'
import 'allotment/dist/style.css'
 
interface SplitProps
  extends React.ComponentPropsWithoutRef<typeof Allotment>,
    Omit<SplitPaneStyles, keyof React.ComponentPropsWithoutRef<typeof Allotment>> {}
 
const Split = React.forwardRef<React.ComponentRef<typeof Allotment>, SplitProps>(
  ({ className, ...props }, forwardedRef) => {
    const styles = splitPaneStyles()
    return <Allotment ref={forwardedRef} className={styles.base({ className })} {...props} />
  }
)
 
interface SplitPaneProps
  extends React.ComponentPropsWithoutRef<typeof Allotment.Pane>,
    Omit<SplitPaneStyles, keyof React.ComponentPropsWithoutRef<typeof Allotment.Pane>> {}
 
const SplitPane = React.forwardRef<React.ComponentRef<typeof Allotment.Pane>, SplitPaneProps>(
  ({ className, children, ...props }, forwardedRef) => {
    const styles = splitPaneStyles()
    return (
      <Allotment.Pane ref={forwardedRef} className={styles.pane({ className })} {...props}>
        {children}
      </Allotment.Pane>
    )
  }
)
 
interface SplitPanelProps extends React.ComponentPropsWithoutRef<'div'>, SplitPaneStyles {
  asChild?: boolean
}
 
const SplitPanel = React.forwardRef<HTMLDivElement, SplitPanelProps>(
  ({ className, asChild = false, ...props }, forwardedRef) => {
    const Comp = asChild ? Slot.Root : 'div'
    const styles = splitPaneStyles()
    return <Comp ref={forwardedRef} className={styles.pane({ className })} {...props} />
  }
)
 
Split.displayName = 'Split'
SplitPane.displayName = 'SplitPane'
SplitPanel.displayName = 'SplitPanel'
 
export { Split, SplitPane, SplitPanel }
export type { AllotmentHandle as SplitHandle }

Usage

Imports

import { Split, SplitPane, SplitPanel } from '#/components/split-pane'

Example

Browse the Storybook for more examples.

Anatomy

<Split>
  <SplitPane>
    <SplitPanel />
  </SplitPane>
</Split>
Edit on GitHub

Last updated on

On this page