Split
Overview
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
Play with the settings and preview the component in action:
- Preview
- Code
Preview
Left Content
Right Content
<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
- npm
- yarn
- pnpm
- manual
npx @mindfiredigital/ignix-ui add split
yarn @mindfiredigital/ignix-ui add split
pnpm @mindfiredigital/ignix-ui add 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 './components/ui';
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>
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 (e.g. "300px" , "20rem" ) | "300px" | Minimum width before stacking occurs |
resizable | boolean | false | Allows user to drag and resize split ratio dynamically |
className | string | "" | Additional CSS classes |
children | <Left> and <Right> components | Required | Defines the left and right sections of the split layout |
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>