React Split Pane ライブラリで画面分割を試してみた

React Split Pane ライブラリで画面分割を試してみた

2026.01.14

はじめに

みなさんこんにちは、クラウド事業本部コンサルティング部の浅野です。

最近はクラウドインフラ領域と合わせてアプリ領域の支援もさせていただいており、Reactライブラリを調べる機会も多くなってきました。

皆さんは「React Split Pane」というライブラリをご存知でしょうか。フロントエンドUIにおいて、画面を複数の領域に分割し、ユーザーがそれぞれの領域のサイズを自由に調整できるようにするライブラリです。使えるシチュエーションとして例えばファイル一覧・編集エリア・プレビューなどを同時に表示するエディタ系Webアプリや、複数のグラフやテーブル、ナビゲーションを1画面で操作する分析・管理画面など、情報量が多く、ユーザーごとに最適なレイアウトが異なるUIで活用できます。

公式リポジトリ ライブデモ画面から引用

2026-01-14-react-split-pane-01

今回はこちらのライブラリをNext.js App Router環境で実際に使用してみて学習コストや使用感を確かめてみました。

Github リポジトリ

2026年1月現在も適宜アップデートを続けておりメンテナンスがきちんとされている印象です。
何より「README」が読みやすいですね。備えられた機能が整理されていてわかりやすいです。

https://github.com/tomkp/react-split-pane?tab=readme-ov-file

他にもReactで使える画面分割系のライブラリで候補に上がるのが「React Split」だと思いますが、2026年1月現在、React Split Paneの方が定期的にメンテナンスされており、最新のNext.js環境での動作確認が容易です。本記事ではこの点を踏まえてReact Split Paneを検証対象としました。

主要機能

まず初めに「React Split Pane」を理解する上で抑えたい主要な機能は以下です。

機能 説明
基本的な画面分割(垂直・水平) <SplitPane> タグで <Pane> タグを囲むことで、垂直・水平の画面分割を行えます。また、SplitPane をネストすることで、より複雑なレイアウト構成も可能です。
制御コンポーネント ペインサイズを state で管理できるため、リセットボタンの実装や、外部イベントに応じたレイアウト制御など、柔軟な操作が可能です。
サイズの永続化 localStoragesessionStorage にユーザーが調整したサイズを保存できるため、ページ更新やブラウザ再起動後もレイアウト状態を保持できます。
スナップポイントサイジング ドラッグによるサイズ変更時にスナップポイントを設定することで、特定のキリの良いサイズに吸着するような、扱いやすいリサイズ操作を実現できます。
カスタムディバイダー ドラッグ用の境界線(ディバイダー)の幅・スタイル・挙動をカスタマイズでき、UIやUXに合わせた見た目・操作感を実装できます。

この他にも前提としてスタイリングはtailwind cssやshadowcn/ui などとシームレスに統合できるのでカスタマイズ性は高いです。

やってみた

それでは上記機能を実コード付きで一つずつやってみて使用感を確かめてみます。

使用環境

今回の検証環境を記載します。

  • ライブラリバージョン: react-split-pane@3.0.5
  • フレームワーク: Next.js 15.5.9(App Router)
  • スタイリング: tailwind-css

基本的な画面分割(垂直・水平)

まずは基本の使用方法を確認してみます。
1ファイルにまとめた方がわかりやすいので、今回はページ内で直接ライブラリコンポーネントを使用して表示しています。

app/splitpane-basic/pages.tsx
"use client";

import { Sidebar } from "@/components/Sidebar";
import { SplitPane, Pane } from "react-split-pane";

export const SplitPaneTest = () => {
  return (
    <SplitPane direction="horizontal">
      <Pane minSize="200px" defaultSize={"300px"} className="bg-gray-400">
        <Sidebar />
      </Pane>
      <Pane>
        <SplitPane direction="vertical" resizable>
          <Pane className="bg-blue-400">上のコンテンツ</Pane>
          <Pane className="bg-red-400" defaultSize="200px">
            下のコンテンツ
          </Pane>
        </SplitPane>
      </Pane>
    </SplitPane>
  );
};

分割の定義方法は<SplitPane>directionプロパティを設定して分割方向(水平/垂直)を指定し、子のレイアウトをそれぞれ<Pane>タグで定義して囲うだけでリサイズ可能な画面分割が簡単に作成できます。resizableプロパティがデフォルトでtrueなのでマウスやキーボード操作で画面レイアウトのサイズが変更できるようになっています。

キーボードでの操作方法

  • 矢印キー:stepピクセル単位でサイズを変更します(デフォルト:10ピクセル)
  • Shift + 矢印: より大きなステップでサイズを変更します (デフォルト: 50px)
  • Home:左/上のペインを最小化
  • End:左/上のペインを最大化
  • Esc : ペインのサイズを初期状態に戻す
  • Tab : 区切り線間を移動

実際の動作画面

2026-01-14-react-split-pane-02

制御コンポーネント

続いて各レイアウトのサイズの状態保持を管理したい時に制御されたコンポーネントを以下のように定義できます。

app/splitpane-controlled/pages.tsx
"use client";

import { useState } from "react";
import { SplitPane, Pane } from "react-split-pane";

export default function SplitPaneControlledPage() {
  const [sizes, setSizes] = useState([300, 500]);

  return (
    <div className="w-full h-screen">
      <SplitPane direction="horizontal" onResize={setSizes}>
        <Pane className="bg-blue-200 p-4" size={sizes[0]}>
          <p>Controlledモード: useStateでサイズ管理</p>
          <p className="text-sm text-gray-600">
            サイズ: {Math.round(sizes[0])}px
          </p>
          <button
            className="mt-2 px-3 py-1 bg-blue-500 text-white rounded"
            onClick={() => setSizes([300, 500])}
          >
            リセット
          </button>
        </Pane>
        <Pane className="bg-green-200 p-4" size={sizes[1]}>
          <p className="text-sm text-gray-600">
            サイズ: {Math.round(sizes[1])}px
          </p>
        </Pane>
      </SplitPane>
    </div>
  );
}

上記にようにuseState hookなどで管理するとサイズの状態が保持でき、リセットボタンで初期位置に戻したりより細かな制御が可能になります。

実際の動作画面

このようにリセットボタンなどで初期サイズに戻せる挙動が確認できました。

2026-01-14-react-split-pane-03

サイズの永続化

続いてサイズをlocalstorage, sessionstorageなどに保存できるカスタムフックであるusePersistenceを使ってサイズの永続化を実行してみます。

app/splitpane-persistence/pages.tsx
"use client";

import dynamic from "next/dynamic";
import { SplitPane, Pane } from "react-split-pane";
import { usePersistence } from "react-split-pane/persistence";

const NoSSRContent = dynamic(
  () =>
    Promise.resolve(function Content() {
      const [sizes, setSizes] = usePersistence({ key: "my-layout" });

      return (
        <div className="w-full h-screen">
          <SplitPane direction="horizontal" onResize={setSizes}>
            <Pane className="bg-blue-200" size={sizes[0] || 300}>
              <div className="p-4">
                <h3 className="font-bold">サイズの永続化</h3>
                <p className="text-sm">usePersistenceフックを使用</p>
              </div>
            </Pane>
            <Pane className="bg-green-200" size={sizes[1]}>
              <div className="p-4">
                <p className="text-sm">リロードしてもサイズ維持</p>
              </div>
            </Pane>
          </SplitPane>
        </div>
      );
    }),
  { ssr: false }
);

export default function SplitPanePersistencePage() {
  return <NoSSRContent />;
}

実際の動作画面

以下のようにページをリロードしてもリサイズが保持されていることが確認できました。

2026-01-14-react-split-pane-04

スナップポイントサイジング

続いてはマウス操作などで特定のサイズに設定しやすくするスナップポイントサイジングを試してみます。

app/splitpane-snappoints/pages.tsx
"use client";

import { SplitPane, Pane } from "react-split-pane";

export default function SplitPaneSnapPointsPage() {
  const snapPoints = [200, 400, 600]; // スナップポイント: これらの値に近づくと吸着する

  return (
    <div className="w-full h-screen">
      <SplitPane
        direction="horizontal"
        snapPoints={snapPoints}
        snapTolerance={20}
      >
        <Pane className="bg-purple-200" defaultSize="300px" minSize="100px">
          <div className="p-4">
            <h3 className="font-bold mb-2">スナップポイント</h3>
            <p className="text-sm">200px, 400px, 600px にサイズが吸着する</p>
          </div>
        </Pane>
        <Pane className="bg-orange-200">
          <div className="p-4">
            <p className="text-sm">ドラッグしてスナップ動作を確認</p>
            <div className="mt-4 text-xs text-gray-600">
              <p>snapTolerance: 20pxにより</p>
              <p>(20px以内に近づくと吸着)</p>
            </div>
          </div>
        </Pane>
      </SplitPane>
    </div>
  );
}

snapPoints配列に吸着してほしいサイズを定義し、<SplitPane>タグに設定できます。またsnapToleranceプロパティによって指定したpxにどれだけ近づいた時に吸着するかも指定して操作感を設定できます(今回は20px)。

実際の動作画面

このように吸着があることでサイジングがしやすくなり、UXの利便性が向上しました。

2026-01-14-react-split-pane-05

カスタムディバイダー

最後にレイアウトの境界線であるディバイダーをカスタマイズしてみます。

app/splitpane-custom-divider/pages.tsx
"use client";

import { SplitPane, Pane } from "react-split-pane";
import type { DividerProps } from "react-split-pane";
import { GripVertical } from "lucide-react"; // アイコンライブラリ

// カスタムDivider: アイコンなど dividerClassName では不可能な表現
const CustomDivider = ({
  isDragging,
  direction,
  currentSize,
  minSize,
  maxSize,
  index,
  disabled,
  ...domProps
}: DividerProps) => (
  <div
    {...domProps}
    className={`w-3 h-full cursor-col-resize flex items-center justify-center
      ${isDragging ? "bg-blue-400" : "bg-gray-100 hover:bg-gray-200"}`}
  >
    <GripVertical
      size={12}
      className={isDragging ? "text-white" : "text-gray-400"}
    />
  </div>
);

export default function SplitPaneCustomDividerPage() {
  return (
    <div className="w-full h-screen">
      <SplitPane direction="horizontal" divider={CustomDivider}>
        <Pane className="bg-slate-50 p-4" defaultSize="300px">
          <p className="text-m text-gray-600">縦線: カスタムDivider</p>
          <p className="text-sm text-gray-400">
            アイコン表示 / ドラッグ中は青+白アイコン
          </p>
        </Pane>
        <Pane>
          <SplitPane
            direction="vertical"
            dividerClassName="!h-3 !w-full cursor-ns-resize bg-gray-100 hover:bg-gray-500"
          >
            <Pane className="bg-slate-100 p-4" defaultSize="50%">
              <p className="text-m text-gray-600">横線: dividerClassName</p>
              <p className="text-sm text-gray-400">
                Tailwindのみ / ホバーで色変化
              </p>
            </Pane>
            <Pane className="bg-slate-200 p-4">
              <p className="text-m text-gray-600">下部</p>
            </Pane>
          </SplitPane>
        </Pane>
      </SplitPane>
    </div>
  );
}

境界線のスタイリングは基本的に自由にできますが、上記の例ではカスタムディバイダーコンポーネントを作成して<SplitPane>タグのdividerプロパティに読み込む方法と、Tailwind CSSのみを使用して<SplitPane>タグに直接dividerClassNameプロパティを設定してスタイリングを表現しています。

実際の動作画面

このようにホバー時やドラッグ時に色を変更したり、アイコンをつけたりすることで、よりみやすい境界線を再現することができました。

2026-01-14-react-split-pane-06

最後に

今回は「React Split Pane」ライブラリをNext.js環境で使用して使用感を確認してみました。お手軽に画面分割レイアウトが実装できて、覚えることも少ないので比較的手を出しやすいライブラリなのではないでしょうか。

ただReactでは公式サンプル通りに動く挙動もNext.jsでは少し考慮が必要がなパターンもあったので注意が必要だと感じました。

READMEを読んでこのライブラリなら要件を満たせそうだと思っていても、いざ組み込んでみると細かい調整が必要だったり、条件次第では少し厳しそうだなと思うこともあります。こういう部分は、やはり実際に使ってみないと分からないですね。

今後もこうした検証を大事にしながら、実装してみて分かったことを記事にまとめていければと思います。今回は以上です。

この記事をシェアする

FacebookHatena blogX

関連記事