Lightweight JavaScript Split Pane Library


Build IDE-style sidebars, editor and preview stacks, and multi-column dashboards in plain HTML and JavaScript. hcg-split-pane is a zero-dependency library built on the Pointer Events API, so mouse, touch, and pen input share one code path. Split two, three, or more panes in one instance; nest horizontal and vertical splits; clamp each pane with min and max sizes; and use percentage or pixel-based sizes without React, jQuery, or a heavy panel toolkit.

On this page you will find live demos, installation (direct download, npm, CDN), a full options reference, React notes, and copy-paste examples for nested splits, multi-pane layouts, pixel sizes, and callbacks.

What is hcg-split-pane?

hcg-split-pane is a lightweight vanilla JavaScript library for resizable split layouts. Call new HcgSplitPane() on a container with two or more child panes (or pass a panes array of selectors), drag gutters to resize, set per-pane minimum and maximum sizes in pixels, and listen to onDragStart, onDrag, and onDragEnd callbacks - without React, jQuery, or any other dependency.

hcg-split-pane examples: horizontal sidebar split, vertical editor and terminal stack, and nested IDE-style layout
hcg-split-pane examples: horizontal sidebar split, vertical editor and terminal stack, and nested IDE-style layout.

Why use hcg-split-pane?

Most split-pane solutions are React components or larger layout toolkits when you only need a resizable sidebar or a simple editor and preview stack. react-split-pane requires React; Split.js and allotment are excellent but may be more than you need for a plain HTML page.

hcg-split-pane fills that gap: a small, dependency-free library built on Pointer Events for mouse, touch, and pen. It suits vanilla pages, React or Vue dashboards, and nested IDE-style layouts without pulling in a framework-specific panel library. See the comparison table for how it differs from react-split-pane and Split.js, and Features for the full capability list.

Live Demo

Drag the gutters below. Each example shows a different option. For every demo in one place, open the full interactive demo page. hcg-split-pane live demo

Horizontal split

Side-by-side panes with a vertical gutter. Default 50/50.

Left

Sidebar or navigation.

Right

Main content area.

Vertical split

Stacked panes with a horizontal gutter - editor above terminal.

Editor

Top panel.

Terminal

Bottom panel.

Three columns

One instance, three panes - sizes: [20, 55, 25].

Sidebar
Editor
Panel
Minimum pane sizes

Sidebar cannot shrink below 160px; main cannot shrink below 120px.

Sidebar (min 160px)
Main (min 120px)

Comparison Table

How hcg-split-pane compares with common alternatives.

Feature hcg-split-pane react-split-pane Split.js / allotment
DependenciesNoneRequires ReactVaries
File sizeSmall (one JS file + CSS)React component + peer depsLarger multi-pane toolkits
Framework requirementNone (script tag friendly)React onlyVanilla or React-focused
Multi-pane (3+)Built in - one instance, N panesTypically two panes per componentBuilt in
Nested horizontal + verticalMultiple instancesNested React componentsMultiple instances
Min / max pane sizesPer-pane px min and maxminSize propminSize / maxSize (varies)
Pixel-based sizessizeUnit: 'pixel'Percent-focusedPixel support (varies)
Touch / pointer dragPointer EventsMouse events (varies by fork)Mouse / touch support
Data attributesYes (data-hcg-* + HcgSplitPane.init())NoManual
Lifecycle callbacksYes (onDragStart, onDrag, onDragEnd)onChange (varies)onDrag (varies)

Installation

Direct download

Source code and package:

Or download hcg-split-pane.js and hcg-split-pane.css and include them directly:

HTML
<link rel="stylesheet" href="hcg-split-pane.css">
<script src="hcg-split-pane.js"></script>
npm

Install from npm:

Bash
npm install hcg-split-pane

CommonJS (require):

JavaScript
require("hcg-split-pane/hcg-split-pane.css");
const HcgSplitPane = require("hcg-split-pane");

ESM (import):

JavaScript
import HcgSplitPane from "hcg-split-pane";
import "hcg-split-pane/hcg-split-pane.css";
CDN usage

Load from a CDN with two tags - no npm or bundler required. The global HcgSplitPane constructor is available as soon as the script finishes loading.

jsDelivr:

HTML
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hcg-split-pane@1/hcg-split-pane.css">
<script src="https://cdn.jsdelivr.net/npm/hcg-split-pane@1/hcg-split-pane.js"></script>

unpkg:

HTML
<link rel="stylesheet" href="https://unpkg.com/hcg-split-pane@1/hcg-split-pane.css">
<script src="https://unpkg.com/hcg-split-pane@1/hcg-split-pane.js"></script>

Replace @1 or @1.0.0 with the release you want. Load CSS in <head> before the script. You can also self-host by uploading hcg-split-pane.js and hcg-split-pane.css to your own server.

Basic Usage

Give a container an explicit height, include the CSS and JS files, then pass a selector or DOM element to new HcgSplitPane(). Direct children become panes unless you pass a panes array.

HTML
<div id="split" style="height: 320px;">
  <div>Left panel</div>
  <div>Right panel</div>
</div>
HTML
const split = new HcgSplitPane('#split', {
  direction: 'horizontal',
  sizes: [50, 50],
  onDragEnd(detail) {
    console.log('Sizes:', detail.sizes);
  }
});
Horizontal and vertical direction

Set direction: 'horizontal' for side-by-side panes or 'vertical' for stacked panes. Toggle at runtime with setOption('direction', 'vertical').

JavaScript
new HcgSplitPane('#split-v', {
  direction: 'vertical',
  sizes: [40, 60]
});

Demo - Horizontal | Demo - Vertical


Three or more panes

Pass one entry in sizes and minSize per pane. One gutter is inserted between each pair.

JavaScript
new HcgSplitPane('#split-3col', {
  direction: 'horizontal',
  sizes: [20, 55, 25],
  minSize: [120, 200, 150]
});

Demo - Three columns | Demo - Three rows


Nested splits

Create multiple instances when you need rows and columns together - for example a sidebar on the left and an editor/preview stack on the right.

JavaScript
new HcgSplitPane('#outer', {
  direction: 'horizontal',
  sizes: [30, 70]
});

new HcgSplitPane('#inner', {
  direction: 'vertical',
  sizes: [55, 45]
});

Demo - Nested split


Pick panes by selector

Use the panes option when panes are not direct children, or when toggling a panel at runtime.

JavaScript
new HcgSplitPane('#preview-box', {
  direction: 'vertical',
  sizes: [55, 45],
  panes: ['#preview', '#console']
});

Demo - Toggle inner split


Min and max pane sizes

Set per-pane limits in pixels. Use a number for the same limit on every pane, or an array with one value per pane.

JavaScript
new HcgSplitPane('#split', {
  direction: 'horizontal',
  sizes: [30, 70],
  minSize: [200, 100],
  maxSize: [320, Infinity]
});

Demo - Min and max sizes


Pixel-based sizes

Set sizeUnit: 'pixel' so getSizes() and setSizes() use pixels (rounded).

JavaScript
const split = new HcgSplitPane('#split', {
  sizeUnit: 'pixel',
  sizes: [180, 360],
  maxSize: [240, Infinity]
});

split.getSizes();   // => [180, 412] (px, rounded)

Demo - Pixel sizes


Set sizes programmatically

Call setSizes([...]) or read the current sizes with getSizes().

JavaScript
const split = new HcgSplitPane('#split', { sizes: [35, 65] });
split.setSizes([50, 50]);
const sizes = split.getSizes();

Demo - setSizes() and getSizes()


Change options at runtime

Use setOption(name, value) or option(name, value) on a live instance. Read values with option(name).

JavaScript
split.setOption('direction', 'vertical');
split.setOption('minSize', [160, 120]);
split.setOption('gutterSize', 8);

Demo - setOption() at runtime


Dynamic add and remove panes

There is no addPane() API. Show or hide DOM nodes, call destroy(), then create a new instance with an updated panes list.

JavaScript
split.destroy();
split = new HcgSplitPane('#host', {
  panes: ['#a', '#b', '#c'],
  sizes: [25, 50, 25]
});

Demo - Dynamic add/remove panes

Features

Everything included in the library at a glance:

  • Zero dependencies - one JS file and one CSS file.
  • Pointer Events - mouse, touch, and pen through one code path.
  • Multi-pane splits - two, three, or N panes in one instance.
  • Horizontal and vertical - side-by-side or stacked; switch direction at runtime.
  • Nested layouts - combine multiple instances on different axes.
  • Min and max sizing - per-pane px limits stop the gutter at each edge.
  • Pixel or percent sizes - sizeUnit: 'pixel' for fixed-style sidebars.
  • Panes by selector - optional panes array for flexible DOM structure.
  • Size persistence - stores last sizes in data-hcg-sizes on the container.
  • Data attributes - data-hcg-split-pane plus option attributes; call HcgSplitPane.init() when ready.
  • Runtime options - change any option later with option() / setOption().
  • Multiple elements - one selector can return an array of instances.
  • Callbacks - onDragStart, onDrag, and onDragEnd with live size data.
  • Instance API - enable, disable, getSizes, setSizes, and destroy.
  • UMD / ESM / global - works with bundlers, require, or a plain script tag.
  • Small footprint - tiny library; works in every modern browser.

Using with React

Create the split-pane instance inside a useEffect hook and clean it up with destroy() when the component unmounts.

JavaScript
import { useEffect, useRef } from "react";
import HcgSplitPane from "hcg-split-pane";
import "hcg-split-pane/hcg-split-pane.css";

function EditorLayout() {
  const hostRef = useRef(null);
  const splitRef = useRef(null);

  useEffect(() => {
    splitRef.current = new HcgSplitPane(hostRef.current, {
      direction: "horizontal",
      sizes: [30, 70]
    });
    return () => splitRef.current?.destroy();
  }, []);

  return (
    <div ref={hostRef} style={{ height: 400 }}>
      <div>Sidebar</div>
      <div>Editor</div>
    </div>
  );
}

Data Attributes

Every option that takes a simple value can be set in HTML. Mark containers with data-hcg-split-pane, then call HcgSplitPane.init() once the DOM is ready.

AttributeMaps to optionExample
data-hcg-split-paneinit targetdata-hcg-split-pane
data-hcg-directiondirectiondata-hcg-direction="horizontal"
data-hcg-sizessizesdata-hcg-sizes="35,65"
data-hcg-size-unitsizeUnitdata-hcg-size-unit="pixel"
data-hcg-min-sizeminSizedata-hcg-min-size="120,200"
data-hcg-max-sizemaxSizedata-hcg-max-size="240,Infinity"
data-hcg-gutter-sizegutterSizedata-hcg-gutter-size="8"
data-hcg-disableddisableddata-hcg-disabled
data-hcg-sizes (stored)restored sizesdata-hcg-sizes="35,65" (written on drag end)
HTML
<div
  data-hcg-split-pane
  data-hcg-direction="horizontal"
  data-hcg-sizes="35,65"
  data-hcg-min-size="120,160">
  <div>Left</div>
  <div>Right</div>
</div>
JavaScript
HcgSplitPane.init(); // every [data-hcg-split-pane] element

To initialize elements added later, call HcgSplitPane.init() again, or call the constructor directly on the new element.

Options Reference

Pass these as the second argument to new HcgSplitPane(element, options).

OptionTypeDefaultDescription
direction'horizontal' | 'vertical''horizontal'Split axis.
panes(string | Element)[] | nullnullPane selectors or elements; default=host children.
sizesNumber[]even splitInitial sizes - percent or px per sizeUnit.
sizeUnit'percent' | 'pixel''percent'Unit for sizes, getSizes(), setSizes().
minSizeNumber | Number[]0Minimum pane size in pixels.
maxSizeNumber | Number[]InfinityMaximum pane size in pixels.
gutterSizeNumber6Gutter width or height in pixels.
disabledBooleanfalseDisable gutter dragging.
onDragStartFunction or nullnullFired when a pointer drag begins. Receives (detail).
onDragFunction or nullnullFired while dragging. Receives (detail).
onDragEndFunction or nullnullFired when a pointer drag ends. Receives (detail).

detail is { event, sizes, gutterIndex }.

Instance Methods

The constructor returns a split-pane instance with the following methods.

MethodDescription
option(name)Gets an option value.
option(name, value)Sets an option value. Returns the instance for chaining.
setOption(name, value)Alias for option(name, value). Re-applies layout when direction, sizes, or limits change.
getSizes()Returns current sizes as an array (percentages, or pixels when sizeUnit: 'pixel').
setSizes(sizes)Sets sizes; length must match pane count; clamped to min/max. Updates data-hcg-sizes.
enable()Turns gutter dragging on. Returns the instance for chaining.
disable()Turns gutter dragging off without removing listeners. Returns the instance.
destroy()Removes gutters, restores original DOM when panes was used, strips listeners. Use this for SPA or framework cleanup.

Read the library version from the static property:

JavaScript
console.log(HcgSplitPane.version);

Static helpers on the constructor:

JavaScript
HcgSplitPane.init();        // every [data-hcg-split-pane] element
HcgSplitPane.destroyAll();  // destroy every active instance

var items = HcgSplitPane('.layout', { sizes: [30, 70] });
if (Array.isArray(items)) {
  items.forEach(function (s) { s.disable(); });
}

Callbacks

Pass lifecycle hooks as option functions. Each callback receives a single detail object. Inside the callback, this is the HcgSplitPane instance.

Function signature
JavaScript
onDragStart(detail) { /* ... */ }
onDrag(detail)      { /* ... */ }
onDragEnd(detail)   { /* ... */ }
detail object
PropertyTypeDescription
eventPointerEventThe native pointer event that triggered the callback.
sizesNumber[]Current pane sizes (percent or px per sizeUnit).
gutterIndexNumberActive gutter index (0=between pane 0 and 1).
When each callback runs
CallbackWhen it runs
onDragStartPointer down on a gutter; drag begins.
onDragPointer moves while dragging; fires on every move.
onDragEndPointer released; final sizes are written to data-hcg-sizes.
Example
JavaScript
new HcgSplitPane('#split', {
  onDragStart(detail) {
    console.log('Gutter', detail.gutterIndex, 'sizes', detail.sizes);
  },
  onDrag(detail) {
    console.log('Dragging', detail.sizes);
  },
  onDragEnd(detail) {
    console.log('Done', detail.sizes);
  }
});

CSS Classes

hcg-split-pane adds class names you can target for styling. Gutter elements are injected between panes. The default stylesheet draws a centered three-dot grip on each gutter with a CSS ::after pseudo-element (no extra DOM nodes).

ClassApplied to
hcg-split-paneThe container element.
hcg-split-pane-horizontalContainer when direction: 'horizontal' (side-by-side panes).
hcg-split-pane-verticalContainer when direction: 'vertical' (stacked panes).
hcg-split-pane_paneEach pane element.
hcg-split-pane_gutterEach draggable gutter between panes. Default styles include a centered dot grip via ::after (stacked dots for a vertical gutter, row of dots for a horizontal gutter).
hcg-split-pane_gutter-activeApplied to the gutter being dragged. Uses a stronger background color and overrides hover while active.
hcg-split-pane-disabledContainer while dragging is disabled.
body.hcg-split-pane-dragging<body> during a pointer drag (global resize cursor).

Theme variables (set on the split container or a parent):

  • --hcg-split-gutter-bg - default gutter background
  • --hcg-split-gutter-hover - gutter background on hover
  • --hcg-split-gutter-active - gutter background while dragging
  • --hcg-split-gutter-grip - dot grip color
  • --hcg-split-gutter-grip-hover - dot grip color on hover

Hide or restyle the default grip with CSS only:

CSS
/* Hide the default dot grip */
.hcg-split-pane_gutter::after {
  display: none;
}

/* Theme the gutter bar and grip */
.hcg-split-pane {
  --hcg-split-gutter-bg: rgba(99, 102, 241, 0.18);
  --hcg-split-gutter-hover: rgba(99, 102, 241, 0.35);
  --hcg-split-gutter-active: rgba(67, 56, 202, 0.92);
  --hcg-split-gutter-grip: rgba(71, 85, 105, 0.55);
  --hcg-split-gutter-grip-hover: rgba(71, 85, 105, 0.75);
}

Browser Support

hcg-split-pane works in all modern browsers that support the Pointer Events API and flexbox.

BrowserSupported
Google ChromeYes
Mozilla FirefoxYes
Microsoft EdgeYes
SafariYes
OperaYes
Mobile browsersYes (touch gutter dragging supported)

License

Released under the MIT License. Free for personal and commercial use. Copyright HTML Code Generator.

Frequently asked questions

Does hcg-split-pane have any dependencies?

No. hcg-split-pane is plain vanilla JavaScript with zero dependencies. Include hcg-split-pane.js and hcg-split-pane.css and you are ready to go.

Does hcg-split-pane work on touch devices?

Yes. It is built on the Pointer Events API, so mouse, touch, and pen input all work through one code path. Gutters set touch-action: none so dragging does not scroll the page accidentally.

Can hcg-split-pane split more than two panes?

Yes. One HcgSplitPane instance supports two, three, or more panes in a single row or column. Pass sizes and minSize arrays with one value per pane, for example sizes: [20, 55, 25] for a three-column layout.

Can I use hcg-split-pane with React?

Yes. Create the HcgSplitPane instance inside a useEffect hook, keep a ref to the container element, and call destroy() in the cleanup function when the component unmounts. The Using with React section above has a full example.

Can I load hcg-split-pane from a CDN?

Yes. Add <link> and <script> tags for hcg-split-pane.css and hcg-split-pane.js from jsDelivr, unpkg, or your own hosted copy, then call new HcgSplitPane('.selector'). The Installation section above includes CDN usage examples.