Dark Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A lightweight, framework-agnostic split-pane library for resizable layouts. Zero dependencies. Modern Pointer Events. CSS-variable driven sizing.

License

Notifications You must be signed in to change notification settings

wutility/split-views

Repository files navigation

SplitViews

A lightweight, framework-agnostic split-pane library for resizable layouts.
Zero dependencies. Modern Pointer Events. CSS-variable driven sizing.

  • Modern: Uses Pointer Events + setPointerCapture (no global listeners)
  • Performant: Batched DOM writes, CSS variables for sizes, minimal reflows
  • Composable: Works with nested splits, no framework required
  • Accessible: ARIA roles, orientations, keyboard focusable gutters


import SplitViews from "split-views";

Or include it via jsDelivr CDN (UMD):

<script src="https://cdn.jsdelivr.net/npm/split-views/dist/index.umd.min.js">script>

Quick Start

HTML:

<div id="editor" class="split-root" style="height: 400px">
<div>Left Panediv>
<div>Right Panediv>
div>

JavaScript:

{ console.log("resizing...", sizes); }, onDragEnd: (sizes) => { console.log("final sizes:", sizes); }, });">import SplitViews from "splitviews";

const split = SplitViews({
root: "#editor",
direction: "horizontal", // 'vertical' or 'horizontal' (default)
gutterSize: 8,
sizes: [30, 70], // percentages; defaults to equal split
minSize: [120, 200], // px per pane or single px applied to all
snapOffset: 8, // px tolerance before snapping to min
onDrag: (sizes) => {
console.log("resizing...", sizes);
},
onDragEnd: (sizes) => {
console.log("final sizes:", sizes);
},
});

Options

Option Type Default Description
root HTMLElement | string required Container element or selector. Children become panes.
direction 'horizontal' | 'vertical' 'horizontal' Split direction.
gutterSize number 10 Gutter thickness in px.
gutterClassName string 'split-gutter' Class applied to each gutter.
minSize number | number[] 0 Per-pane minimum size in px (array) or single px for all.
sizes number[] equal split Initial sizes in percentages.
snapOffset number 0 Extra px tolerance before snapping to min.
onDrag (sizes:number[])=>void -- Called on every drag frame.
onDragEnd (sizes:number[])=>void -- Called when dragging stops.

API

  • destroy(): Removes gutters and resets styles
  • setSizes(sizes: number[]): Programmatically set pane sizes
  • getSizes(): number[]: Get current pane sizes

Styling

The library sets:

  • display: flex and flex-direction on root
  • flex-basis per pane (via CSS variables)
  • Basic cursor and touch-action on gutters

You control the look of gutters:

.split-root {
contain: layout size style; /* hint for performance */
}

.split-gutter {
background: transparent;
position: relative;
}

/* Visible hairline */
.split-gutter::before {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.1);
}

.split-gutter:hover::before {
background: rgba(0, 0, 0, 0.2);
}

CSS variables you can use:

  • --pane--size: applied as flex-basis for each pane
  • --split-gutter-size: gutter thickness
  • --split-cursor: cursor type (col-resize / row-resize)

Accessibility

Gutters automatically have:

  • role="separator"
  • aria-orientation="vertical" (for horizontal split) or "horizontal" (for vertical split)
  • tabIndex="0" so they can be focused

Nested Splits

You can nest multiple instances:

const outer = SplitViews({ root: "#root", direction: "horizontal" });
const inner = SplitViews({
root: '#root [data-split-pane="1"]',
direction: "vertical",
});

Each instance manages only its direct children.


Performance Notes

  • Uses setPointerCapture - no global listeners.
  • DOM writes batched with requestAnimationFrame.
  • CSS variables used for sizes - fast style recalculation.
  • Avoid heavy work in onDrag; debounce if needed.
  • Clean destroy() ensures no leaks.

Browser Support

  • Chromium, Firefox, Safari (modern versions with Pointer Events).
  • No IE support (Pointer Events required).

License

MIT (c) 2025

About

A lightweight, framework-agnostic split-pane library for resizable layouts. Zero dependencies. Modern Pointer Events. CSS-variable driven sizing.

Topics

Resources

Readme

License

MIT license

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2