Split view
betaThe one two-pane layout: aside next to the main content (rail | detail, list | reader, work | discussion); bar above, not resizable.
React lives in the app (SplitView.tsx); stories render its markup 1:1. Beta 4 Oct 2026: stories + usage + a11y done; canon after AD approval. Open: settings (OpravneniRole, SadyOpravneniTab) use SplitView with fill={false} although DS-SPLITVIEW lists Settings as not-SplitView, and pass gap without divider="gap" (no effect).
Used in 32 files · 28 areas · 33× — components/GlobalSearch, components/agent-desk, components/company, pages/AccountingInvoiceDetailPage, pages/AccountingInvoiceEditPage, pages/AsistentPlochaPage …
The one two-pane layout of the application: an aside next to the main content — record rail | detail, config | preview, list | reader, work | discussion. Every two-column screen uses it; nobody writes a new two-column grid. React SplitView in apps/web/src/components/SplitView.tsx (app-side); CSS apps/web/src/ds/split-view.css (.sv, .sv-aside, .sv-main, .sv-pad, modifiers .sv-r, .sv-div-line, .sv-div-gap, .sv-fill, .sv-collapse); the phone stack lives in apps/web/src/ds/responsive.css. Recipes and migration history: docs/DS-SPLITVIEW.md in the app repo.
When to use
- A screen whose body is two columns that live side by side: a record (rail | detail), a calculator or builder (config | preview), a list with a reader (Aktivity, DPH, Deník), a project (work | discussion).
- The body under a bar — PageHeader or Section top bar sits above the split across the full width; the split is only what is under it.
When not to use
- Settings (navigation | feed), the guide (filters stacked above results), single-column screens (Pokladna, Tým), mail (list + modal) — they are not aside | main.
- A layout inside a card or a dialog; the split is a page body.
- Anything that needs the user to drag the divider — the split is not resizable, by decision.
Anatomy
- Root
div.sv: a gridvar(--sv-aside) minmax(0, 1fr). Default aside widthclamp(356px, 31%, 452px)(minmax(320px, 0.82fr)when the aside is on the right).asideWidthsets--sv-aside— a number is px, a string any grid track. - Panes
.sv-asideand.sv-main: flex columns that may shrink below their content (min-width/min-height: 0). - Divider:
divider="line"(default) = a--borderhairline on the aside's inner edge;divider="gap"= a gap--sv-gap(default--sp-6) instead of the line. asidePosition="right"(.sv-r): the aside sits on the right and the main pane comes FIRST in the DOM.fill(default on,.sv-fill): the split fills the height under the bar and each pane scrolls on its own. It needs a flex-column parent with a height (.pron a page).fill={false}: both panes hug their content and scroll together in the parent.collapse(.sv-collapse): one column below 1080px on desktop (Projekt). Independent of the phone stack.- Gutter
.sv-padon a pane without its own gutter (rail, form): padding--sp-5 --sp-5 --sp-6, flex column with--sp-5gap, and--il-gutter: var(--sp-5)for embedded item lists. - Phone (≤720px, automatic): the panes stack — aside on top for
.sv, main on top for.sv-r; the line becomes a horizontal hairline, the gap a row gap; withfillthe whole page scrolls once.
Best practices
- Use the default width unless the screen is one of the recipes (Schůzka
clamp(320px, 27%, 396px), list | reader372, narrow filter list280, discussion on the rightclamp(300px, 24%, 360px)). - Wrap a bare pane in
.sv-pad; leave panes that bring their own gutter alone. - Use
fill={false}when the split sits inside something that already scrolls. - Keep the bar above the split, full width.
- Write a new two-column grid or a new class next to
.sv. - Invent widths or breakpoints, or add a resize handle.
- Put inline padding on
.sv-aside— that is what.sv-padis for. - Use
fillinside a region that already scrolls (two scrollbars, cut-off panes). - Pass
gapwithoutdivider="gap"— with the line divider it has no effect. - Nest a split inside a split.
Content
- The aside is the context (who, what, settings, list); the main pane is where the work happens. The aside never repeats the title shown in the bar.
- An empty main pane says what to do in one short line ("Vyberte záznam vlevo"), no illustration and no explanation.
- While loading, both panes keep their place and show skeletons, so nothing jumps when the data arrive.
Related
record-rail— the usual content of the aside on a record.section-top-bar,page-header— the bar above the split.command-palette— built on the same.sv-*panes (.gsp2).- Stories:
components--split-view--default,--variants,--sizes,--states,--composition.
Source: docs/app-shell/split-view.usage.md · GitLab