Split
The Split component simplifies the creation of two-column layouts such as sidebars with content, image and text sections, or dashboard layouts.
It supports ratios, gaps, responsive stacking, and optional resizing.
- Preview
- Code
Preview
Left Content
Right Content
import { Split, Left, Right } from '@ignix-ui/split';
<Split
ratio="50:50"
gap="normal"
mobile="stack"
resizable={false}
>
<Left>
<div className="p-4 bg-red-500 text-white rounded">Left Content</div>
</Left>
<Right>
<div className="p-4 bg-yellow-500 text-white rounded">Right Content</div>
</Right>
</Split>
Installation
- CLI
- Manual
ignix add component split
import { cn } from "../../../utils/cn";
import { useRef, useState, useEffect, type ReactNode } from "react";
export type Ratio = "30:70" | "40:60" | "50:50" | "60:40" | "70:30";
export type MobileMode = "stack" | "keep-split" | "reverse";
export type Gap = "none" | "small" | "normal" | "large";
interface SplitProps {
children: ReactNode;
ratio?: Ratio;
mobile?: MobileMode;
gap?: Gap;
minWidth?: string;
resizable?: boolean;
className?: string;
}
const gapClasses: Record<Gap, string> = {
none: "gap-0",
small: "gap-2",
normal: "gap-4",
large: "gap-8",
};
export function Split({
children,
ratio = "50:50",
mobile = "keep-split",
gap = "normal",
minWidth = "300px",
resizable = false,
className,
}: SplitProps) {
const [sizes, setSizes] = useState(ratio.split(":").map(Number));
const containerRef = useRef<HTMLDivElement>(null);
// Update sizes when ratio prop changes
useEffect(() => {
setSizes(ratio.split(":").map(Number));
}, [ratio]);
const handleDrag = (e: MouseEvent) => {
if (!containerRef.current) return;
const rect = containerRef.current.getBoundingClientRect();
const total = rect.width;
const left = e.clientX - rect.left;
const leftPct = Math.max(10, Math.min(90, (left / total) * 100));
setSizes([leftPct, 100 - leftPct]);
};
return (
<div
ref={containerRef}
className={cn(
"flex w-full",
gapClasses[gap],
mobile === "stack" && "flex-col sm:flex-row",
mobile === "reverse" && "flex-col-reverse sm:flex-row-reverse",
className
)}
style={{ minWidth }}
>
{/* Left Panel */}
<div className="flex-shrink-0" style={{ flexBasis: `${sizes[0]}%` }}>
{Array.isArray(children) ? children[0] : children}
</div>
{/* Optional Resize Handle */}
{resizable && (
<div
className="w-1 cursor-col-resize bg-gray-300 dark:bg-gray-700"
onMouseDown={() => {
const move = (ev: MouseEvent) => handleDrag(ev);
const up = () => {
document.removeEventListener("mousemove", move);
document.removeEventListener("mouseup", up);
};
document.addEventListener("mousemove", move);
document.addEventListener("mouseup", up);
}}
/>
)}
{/* Right Panel */}
<div className="flex-1" style={{ flexBasis: `${sizes[1]}%` }}>
{Array.isArray(children) ? children[1] : null}
</div>
</div>
);
}
// Helpers for clarity
export function Left({ children }: { children: ReactNode }) {
return <>{children}</>;
}
export function Right({ children }: { children: ReactNode }) {
return <>{children}</>;
}
Usage
Import the component:
import { Split, Left, Right } from '@ignix-ui/split';
Basic Example
<Split ratio="30:70" mobile="stack" gap="normal">
<Left>
<div className="p-4 bg-red-500 text-white rounded">Sidebar</div>
</Left>
<Right>
<div className="p-4 bg-yellow-500 text-white rounded">Main Content</div>
</Right>
</Split>
Examples
Dashboard Layout
- Preview
- Code
Sidebar
Main Dashboard Area
<Split ratio="20:80" gap="large" mobile="keep-split">
<Left>
<div className="bg-gray-900 text-white p-4 rounded">Sidebar</div>
</Left>
<Right>
<div className="bg-gray-100 p-4 rounded">Main Dashboard Area</div>
</Right>
</Split>
Resizable Split
- Preview
- Code
Drag to Resize
Resizable Panel
<Split ratio="50:50" resizable>
<Left>
<div className="bg-red-500 text-white p-4 rounded">Drag to Resize</div>
</Left>
<Right>
<div className="bg-yellow-500 text-white p-4 rounded">Resizable Panel</div>
</Right>
</Split>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
ratio | "30:70" | "40:60" | "50:50" | "60:40" | "70:30" | "50:50" | Defines the column ratio between left and right sections |
gap | "none" | "small" | "normal" | "large" | "normal" | Controls the space between the two sections |
mobile | "stack" | "keep-split" | "reverse" | "stack" | Defines how layout behaves on small screens |
minWidth | string | "300px" | Minimum width before stacking occurs |
resizable | boolean | false | Allows user to drag and resize split ratio dynamically |
className | string | "" | Additional CSS classes |
children | React.ReactNode | Required | Defines the <Left> and <Right> sections of the layout |