Component Porchlight CSS

Split pane

CSS-only horizontal and vertical split panes for explorers, editors, inspectors, and process builder shells.

52 components 51 stable 1 experimental

Command

Search Porchlight

Split pane

The .c-split-pane component gives enterprise app shells a first-class split layout: object explorer plus work surface, editor plus inspector, logs plus details, or process map plus configuration panel. It is CSS-only and dependency-free. Apps own resizing behavior, keyboard handling, saved sizes, and responsive product decisions.

The separator is real rendered HTML. When the split is interactive, use role="separator" with aria-orientation, aria-valuenow, aria-valuemin, and aria-valuemax. When the split is only a visual divider, keep the separator non-focusable and omit the value attributes.

Semantic HTML

<div class="c-split-pane" data-orientation="horizontal" data-collapse="stack">
  <section class="c-split-pane__pane c-split-pane__pane--start">
    <div class="c-split-pane__header">
      <h2 class="c-split-pane__title">Process folders</h2>
    </div>
    <div class="c-split-pane__pane-inner">...</div>
  </section>

  <div
    class="c-split-pane__separator"
    role="separator"
    aria-orientation="vertical"
    aria-valuemin="20"
    aria-valuemax="60"
    aria-valuenow="32"
    tabindex="0"
  ></div>

  <section class="c-split-pane__pane c-split-pane__pane--end">
    <div class="c-split-pane__header">
      <h2 class="c-split-pane__title">Rule editor</h2>
    </div>
    <div class="c-split-pane__pane-inner">...</div>
  </section>
</div>

For horizontal pane layouts, the separator itself has aria-orientation="vertical" because the separator line is vertical. For vertical pane layouts, use aria-orientation="horizontal".

Fixed and Static Splits

<div
  class="c-split-pane"
  data-layout="fixed-start"
  style="--c-split-pane-fixed-size: 18rem;"
>
  <aside class="c-split-pane__pane c-split-pane__pane--start">...</aside>
  <div class="c-split-pane__separator" aria-hidden="true"></div>
  <main class="c-split-pane__pane c-split-pane__pane--end">...</main>
</div>

Use data-layout="fixed-start" for a fixed explorer/sidebar and flexible work surface. Use data-layout="fixed-end" for a fixed inspector/details pane. If the divider is decorative, omit role="separator" and make it unfocusable.

Vertical Split

<div
  class="c-split-pane"
  data-orientation="vertical"
  style="--c-split-pane-start-size: minmax(12rem, 1fr);"
>
  <section class="c-split-pane__pane c-split-pane__pane--start">...</section>
  <div
    class="c-split-pane__separator"
    role="separator"
    aria-orientation="horizontal"
    aria-valuemin="25"
    aria-valuemax="75"
    aria-valuenow="45"
    tabindex="0"
  ></div>
  <section class="c-split-pane__pane c-split-pane__pane--end">...</section>
</div>

Resizing Contract

Porchlight does not resize panes. Your app can update custom properties on the root element:

<div
  class="c-split-pane"
  style="
    --c-split-pane-start-size: minmax(18rem, 34%);
    --c-split-pane-end-size: minmax(0, 1fr);
  "
>
  ...
</div>

When resizing is interactive:

  • Make the separator focusable with tabindex="0".
  • Add role="separator" and the correct aria-orientation.
  • Keep aria-valuenow, aria-valuemin, and aria-valuemax in sync with the current split percentage or application-defined unit.
  • Support pointer resizing and keyboard resizing with arrow keys.
  • Persist user sizes in app state, local storage, user preferences, or the server according to your product needs.
  • Respect min/max sizes so panes do not collapse into unusable controls.
  • If a pane itself scrolls and does not contain keyboard-focusable content, make the pane focusable with tabindex="0" and provide an accessible label.

Responsive Behavior

Add data-collapse="stack" to horizontal splits that should stack in narrow containers. The component uses a container query, so a split pane inside a drawer, tab, or app shell responds to its own width rather than the viewport. For dense enterprise screens where stacking would hide critical data, omit data-collapse and let panes overflow or use product-specific responsive rules.

Each pane is its own scroll container with a stable scrollbar gutter. This keeps tables, editors, and log viewers from sliding under the pane edge when content starts scrolling.

SSR and Framework Compatibility

The component is plain HTML and CSS. It can be emitted by server-rendered apps, hypermedia responses, Web Components, or component frameworks. There are no framework-specific selectors and no JavaScript dependency. A client controller can enhance the separator after render by updating attributes and CSS custom properties without changing the markup contract.

Class Contract

SelectorRole
.c-split-paneGrid container for two panes and one separator.
.c-split-pane__paneScrollable pane.
.c-split-pane__pane--startFirst pane.
.c-split-pane__pane--endSecond pane.
.c-split-pane__separatorDivider or interactive resize handle.
.c-split-pane__pane-innerOptional padded pane body.
.c-split-pane__headerSticky pane header.
.c-split-pane__titleHeader title.
.c-split-pane__descriptionSecondary header text.
[data-orientation="horizontal"]Side-by-side panes.
[data-orientation="vertical"]Stacked panes.
[data-layout="fixed-start"]Fixed first pane.
[data-layout="fixed-end"]Fixed second pane.
[data-collapse="stack"]Stack horizontal panes in narrow containers.
[data-variant="plain"]Remove outer border and radius.

Tokens Exposed

TokenDefaultPurpose
--c-split-pane-start-sizeminmax(16rem, 0.85fr)First pane grid size.
--c-split-pane-end-sizeminmax(0, 1fr)Second pane grid size.
--c-split-pane-fixed-size18rem or 22remFixed pane size for layout variants.
--c-split-pane-separator-size0.75remHit area for the separator.
--c-split-pane-separator-line-size1pxVisible separator line.
--c-split-pane-min-block-size24remMinimum container height.
--c-split-pane-pane-paddingvar(--pl-space-4)Optional inner padding.