Svelte 5 component · fractalsvelte-ui · Layout
SplitPane
A resizable two-pane container with a draggable divider bar supporting horizontal and vertical orientations and minimum size constraints.
Install
SplitPane is a Svelte 5 split pane component in @fractaldesign/fractalsvelte-ui. It works in SvelteKit and in any Svelte 5 app.
pnpm add @fractaldesign/fractalsvelte-uiImport
import { SplitPane } from '@fractaldesign/fractalsvelte-ui';Usage
<SplitPane orientation={'horizontal'} split={50} minSize={15} />Props
Also accepts every attribute of HTMLAttributes, spread onto
the root element.
| Name | Type | Default |
|---|---|---|
orientation | 'horizontal' | 'vertical' | 'horizontal' |
split bindable | number | 50 |
minSize | number | 15 |
class | string | '' |
Snippets
| Name | Type | Default |
|---|---|---|
paneA | Snippet | — |
paneB | Snippet | — |
Source
Show the SplitPane.svelte source
<script lang="ts">
import type { Snippet } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
interface Props extends HTMLAttributes<HTMLDivElement> {
orientation?: 'horizontal' | 'vertical';
split?: number; // percentage 10-90
minSize?: number; // percentage
class?: string;
paneA?: Snippet;
paneB?: Snippet;
}
let {
orientation = 'horizontal',
split = $bindable(50),
minSize = 15,
class: className = '',
paneA,
paneB,
...restProps
}: Props = $props();
let isDragging = $state(false);
let containerEl: HTMLDivElement | undefined = $state();
function handlePointerDown(e: PointerEvent) {
isDragging = true;
(e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
}
function handlePointerMove(e: PointerEvent) {
if (!isDragging || !containerEl) return;
const rect = containerEl.getBoundingClientRect();
if (orientation === 'horizontal') {
const pos = ((e.clientX - rect.left) / rect.width) * 100;
split = Math.min(100 - minSize, Math.max(minSize, pos));
} else {
const pos = ((e.clientY - rect.top) / rect.height) * 100;
split = Math.min(100 - minSize, Math.max(minSize, pos));
}
}
function handlePointerUp() {
isDragging = false;
}
</script>
<div
bind:this={containerEl}
class="f-split-pane {className}"
data-orientation={orientation}
data-dragging={isDragging ? 'true' : undefined}
{...restProps}
>
<div
class="f-pane f-pane-a"
style={orientation === 'horizontal' ? `width: ${split}%;` : `height: ${split}%;`}
>
{#if paneA}
{@render paneA()}
{/if}
</div>
<div
class="f-split-divider"
role="separator"
aria-orientation={orientation}
onpointerdown={handlePointerDown}
onpointermove={handlePointerMove}
onpointerup={handlePointerUp}
onpointercancel={handlePointerUp}
>
<div class="f-split-handle"></div>
</div>
<div
class="f-pane f-pane-b"
style={orientation === 'horizontal' ? `width: ${100 - split}%;` : `height: ${100 - split}%;`}
>
{#if paneB}
{@render paneB()}
{/if}
</div>
</div>
<style>
@layer fractalsvelte-ui.components {
.f-split-pane {
display: flex;
width: 100%;
height: 100%;
min-height: 200px;
box-sizing: border-box;
overflow: hidden;
user-select: none;
}
.f-split-pane[data-orientation='vertical'] {
flex-direction: column;
}
.f-pane {
overflow: auto;
box-sizing: border-box;
}
.f-split-divider {
position: relative;
display: flex;
align-items: center;
justify-content: center;
background: var(--f-border);
transition: background var(--f-duration-fast) var(--f-ease);
flex-shrink: 0;
}
.f-split-pane[data-orientation='horizontal'] .f-split-divider {
width: 6px;
cursor: col-resize;
}
.f-split-pane[data-orientation='vertical'] .f-split-divider {
height: 6px;
cursor: row-resize;
}
.f-split-divider:hover,
.f-split-pane[data-dragging='true'] .f-split-divider {
background: var(--f-primary);
}
.f-split-handle {
width: 2px;
height: 16px;
background: var(--f-border-strong);
border-radius: 1px;
}
.f-split-pane[data-orientation='vertical'] .f-split-handle {
width: 16px;
height: 2px;
}
}
</style>Related components
Stack A linear layout container for organizing child elements in flex columns or rows.BentoCell A modular cell designed for bento grids with configurable column and row track spans.BentoGrid A modern dashboard grid container utilizing dense auto-flow packing to assemble modular bento interfaces…Card A versatile container with structured slots for media, header, content body, and footer actions.ClickableCard An interactive card that functions as a button or anchor link with elevation hover lift and active press…Container A responsive centered container that constrains content width to standardized breakpoints or fluid dimensions.