Blazor Split View
Pane Content #
Pane1 and Pane2 are the required content regions for SplitView.
Navigation
Workspace
Use the two required pane templates to define the resizable primary and secondary regions.
<SplitView Class="border rounded shadow-sm"
Style="height: 360px;">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Pane1</div>
<h5 class="mb-3">Navigation</h5>
<div class="list-group list-group-flush">
<div class="list-group-item">Overview</div>
<div class="list-group-item">Customers</div>
<div class="list-group-item">Orders</div>
<div class="list-group-item">Reports</div>
</div>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Pane2</div>
<h4 class="mb-3">Workspace</h4>
<p class="text-secondary mb-0">Use the two required pane templates to define the resizable primary and secondary regions.</p>
</div>
</Pane2>
</SplitView>Orientation #
Orientation="SplitViewOrientation.Vertical" to stack panes top to bottom with a horizontal divider.
Navigation
The default horizontal orientation places panes side by side with a vertical divider.
Workspace
- Dashboard widgets
- Tables and forms
- Contextual details
Summary
Vertical orientation stacks panes and changes the divider to horizontal dragging.
Details
- Release notes
- Deployment checklist
- Preview output
<div class="small text-uppercase text-secondary mb-2">Horizontal Orientation</div>
<SplitView Class="border rounded shadow-sm mb-4"
Style="height: 320px;"
PrimaryPaneSize="32">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Left Pane</div>
<h5 class="mb-3">Navigation</h5>
<p class="mb-0">The default horizontal orientation places panes side by side with a vertical divider.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Right Pane</div>
<h5 class="mb-3">Workspace</h5>
<ul class="mb-0">
<li>Dashboard widgets</li>
<li>Tables and forms</li>
<li>Contextual details</li>
</ul>
</div>
</Pane2>
</SplitView>
<div class="small text-uppercase text-secondary mb-2">Vertical Orientation</div>
<SplitView Class="border rounded shadow-sm"
Style="height: 420px;"
Orientation="SplitViewOrientation.Vertical"
PrimaryPaneSize="35">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Top Pane</div>
<h5 class="mb-3">Summary</h5>
<p class="mb-0">Vertical orientation stacks panes and changes the divider to horizontal dragging.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Bottom Pane</div>
<h5 class="mb-3">Details</h5>
<ul class="mb-0">
<li>Release notes</li>
<li>Deployment checklist</li>
<li>Preview output</li>
</ul>
</div>
</Pane2>
</SplitView>Primary Pane Size #
PrimaryPaneSize to set the initial percentage allocated to the primary pane.
30%
Set PrimaryPaneSize when you want the initial layout to favor one pane.
70%
The remaining space is automatically assigned to the secondary pane.
<SplitView Class="border rounded shadow-sm"
Style="height: 320px;"
PrimaryPaneSize="30">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Primary Pane</div>
<h5 class="mb-3">30%</h5>
<p class="mb-0">Set <code>PrimaryPaneSize</code> when you want the initial layout to favor one pane.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
<h5 class="mb-3">70%</h5>
<p class="mb-0">The remaining space is automatically assigned to the secondary pane.</p>
</div>
</Pane2>
</SplitView>Primary Pane Size Changed #
@bind-PrimaryPaneSize or PrimaryPaneSizeChanged to react to live divider movement.
Two-way Binding
Drag the divider or use the buttons above to update the same bound value.
Live Value
The parent component stays synchronized through PrimaryPaneSizeChanged.
<div class="d-flex flex-wrap gap-2 mb-3">
<button class="btn btn-outline-secondary btn-sm" @onclick='() => primaryPaneSize = 25'>25%</button>
<button class="btn btn-outline-secondary btn-sm" @onclick='() => primaryPaneSize = 40'>40%</button>
<button class="btn btn-outline-secondary btn-sm" @onclick='() => primaryPaneSize = 60'>60%</button>
<div class="small text-secondary align-self-center">Bound primary pane size: <strong>@primaryPaneSize.ToString("0.##")%</strong></div>
</div>
<SplitView Class="border rounded shadow-sm"
Style="height: 340px;"
MinimumPaneSize="15"
@bind-PrimaryPaneSize="primaryPaneSize">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Primary Pane</div>
<h5 class="mb-3">Two-way Binding</h5>
<p class="mb-0">Drag the divider or use the buttons above to update the same bound value.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
<h5 class="mb-3">Live Value</h5>
<p class="mb-0">The parent component stays synchronized through <code>PrimaryPaneSizeChanged</code>.</p>
</div>
</Pane2>
</SplitView>
@code {
private double primaryPaneSize = 40;
}Minimum Pane Size #
MinimumPaneSize clamps both panes so one side cannot fully collapse while dragging.
25%
The divider cannot move past the 25% threshold, so the primary pane always remains usable.
Protected Layout
The same minimum is enforced from the opposite side, keeping both panes visible.
<SplitView Class="border rounded shadow-sm"
Style="height: 340px;"
PrimaryPaneSize="35"
MinimumPaneSize="25">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">MinimumPaneSize</div>
<h5 class="mb-3">25%</h5>
<p class="mb-0">The divider cannot move past the 25% threshold, so the primary pane always remains usable.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
<h5 class="mb-3">Protected Layout</h5>
<p class="mb-0">The same minimum is enforced from the opposite side, keeping both panes visible.</p>
</div>
</Pane2>
</SplitView>Disabled State #
IsDisabled="true" to keep the layout visible while preventing pointer-based resizing.
Pinned Pane
The layout remains visible, but pointer dragging and hover states are disabled.
Static Layout
Programmatic updates to PrimaryPaneSize still work even when interaction is disabled.
<SplitView Class="border rounded shadow-sm"
Style="height: 320px;"
PrimaryPaneSize="40"
Color="SplitViewColor.Secondary"
IsDisabled="true">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Disabled Divider</div>
<h5 class="mb-3">Pinned Pane</h5>
<p class="mb-0">The layout remains visible, but pointer dragging and hover states are disabled.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
<h5 class="mb-3">Static Layout</h5>
<p class="mb-0">Programmatic updates to <code>PrimaryPaneSize</code> still work even when interaction is disabled.</p>
</div>
</Pane2>
</SplitView>Semantic Color #
Color parameter uses the SplitViewColor enum and maps to shared Bootstrap-backed CSS variables.
blazor.bootstrap.css token mapping.<div class="row g-3">
<div class="col-lg-4">
<SplitView Class="border rounded shadow-sm"
Style="height: 260px;"
PrimaryPaneSize="32"
Color="SplitViewColor.Primary">
<Pane1>
<div class="h-100 p-3 bg-body-tertiary">
<div class="fw-semibold mb-2">Primary</div>
<div class="small text-secondary">Bootstrap semantic color</div>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-3 bg-body">Hover and dragging derive from the same base divider color.</div>
</Pane2>
</SplitView>
</div>
<div class="col-lg-4">
<SplitView Class="border rounded shadow-sm"
Style="height: 260px;"
PrimaryPaneSize="32"
Color="SplitViewColor.Success">
<Pane1>
<div class="h-100 p-3 bg-body-tertiary">
<div class="fw-semibold mb-2">Success</div>
<div class="small text-secondary">Shared CSS variable mapping</div>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-3 bg-body">Use enum values when you want Bootstrap-aligned theming.</div>
</Pane2>
</SplitView>
</div>
<div class="col-lg-4">
<SplitView Class="border rounded shadow-sm"
Style="height: 260px;"
PrimaryPaneSize="32"
Color="SplitViewColor.Dark">
<Pane1>
<div class="h-100 p-3 bg-body-tertiary">
<div class="fw-semibold mb-2">Dark</div>
<div class="small text-secondary">Theme-aware shared CSS</div>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-3 bg-body">The divider color comes from the shared <code>blazor.bootstrap.css</code> token mapping.</div>
</Pane2>
</SplitView>
</div>
</div>Custom Color #
CustomColor when you want to pass a CSS color expression such as var(...) or rgba(...).
CSS Expression Override
This example uses rgba(var(--bs-info-rgb), 0.85) instead of a semantic enum value.
Inline Custom Value
When both are supplied, CustomColor overrides the shared default and semantic enum class.
<SplitView Class="border rounded shadow-sm"
Style="height: 320px;"
PrimaryPaneSize="34"
CustomColor="rgba(var(--bs-info-rgb), 0.85)">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">CustomColor</div>
<h5 class="mb-3">CSS Expression Override</h5>
<p class="mb-0">This example uses <code>rgba(var(--bs-info-rgb), 0.85)</code> instead of a semantic enum value.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Override Precedence</div>
<h5 class="mb-3">Inline Custom Value</h5>
<p class="mb-0">When both are supplied, <code>CustomColor</code> overrides the shared default and semantic enum class.</p>
</div>
</Pane2>
</SplitView>OnResizeStarted #
OnResizeStarted fires once when the pointer first captures the divider.
Drag To Start
Grab the divider to trigger the start event once per interaction.
Event Snapshot
The event args include both pane sizes as percentages.
<div class="row g-3">
<div class="col-lg-8">
<SplitView Class="border rounded shadow-sm"
Style="height: 320px;"
PrimaryPaneSize="38"
OnResizeStarted="HandleResizeStarted">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">OnResizeStarted</div>
<h5 class="mb-3">Drag To Start</h5>
<p class="mb-0">Grab the divider to trigger the start event once per interaction.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
<h5 class="mb-3">Event Snapshot</h5>
<p class="mb-0">The event args include both pane sizes as percentages.</p>
</div>
</Pane2>
</SplitView>
</div>
<div class="col-lg-4">
<div class="border rounded p-3 h-100 bg-body-tertiary">
<div class="fw-semibold mb-2">Start Event</div>
<div class="mb-2">Count: <strong>@count</strong></div>
<div class="mb-2">Primary pane: <strong>@primaryPaneSize.ToString("0.##")%</strong></div>
<div>Secondary pane: <strong>@secondaryPaneSize.ToString("0.##")%</strong></div>
</div>
</div>
</div>
@code {
private int count;
private double primaryPaneSize = 38;
private double secondaryPaneSize = 62;
private void HandleResizeStarted(SplitViewResizeEventArgs args)
{
count++;
primaryPaneSize = args.PrimaryPaneSize;
secondaryPaneSize = args.SecondaryPaneSize;
}
}OnResized #
OnResized streams live primary and secondary pane percentages during drag.
Live Resize Stream
Drag the divider and watch the event payload update continuously.
Current Split
Primary pane: 42%
<div class="row g-3">
<div class="col-lg-8">
<SplitView Class="border rounded shadow-sm"
Style="height: 340px;"
PrimaryPaneSize="42"
OnResized="HandleResized">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">OnResized</div>
<h5 class="mb-3">Live Resize Stream</h5>
<p class="mb-0">Drag the divider and watch the event payload update continuously.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Live Metrics</div>
<h5 class="mb-3">Current Split</h5>
<p class="mb-0">Primary pane: <strong>@primaryPaneSize.ToString("0.##")%</strong></p>
</div>
</Pane2>
</SplitView>
</div>
<div class="col-lg-4">
<div class="border rounded p-3 h-100 bg-body-tertiary">
<div class="fw-semibold mb-2">Resized Event</div>
<div class="mb-2">Primary pane: <strong>@primaryPaneSize.ToString("0.##")%</strong></div>
<div>Secondary pane: <strong>@secondaryPaneSize.ToString("0.##")%</strong></div>
</div>
</div>
</div>
@code {
private double primaryPaneSize = 42;
private double secondaryPaneSize = 58;
private void HandleResized(SplitViewResizeEventArgs args)
{
primaryPaneSize = args.PrimaryPaneSize;
secondaryPaneSize = args.SecondaryPaneSize;
}
}OnResizeEnded #
OnResizeEnded is useful when you only want to persist the final pane sizes after dragging stops.
Persist Final Size
This event fires once after dragging finishes, which is useful for saving layout preferences.
Release The Divider
Only the final percentages are recorded here.
<div class="row g-3">
<div class="col-lg-8">
<SplitView Class="border rounded shadow-sm"
Style="height: 340px;"
PrimaryPaneSize="36"
OnResizeEnded="HandleResizeEnded">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">OnResizeEnded</div>
<h5 class="mb-3">Persist Final Size</h5>
<p class="mb-0">This event fires once after dragging finishes, which is useful for saving layout preferences.</p>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Secondary Pane</div>
<h5 class="mb-3">Release The Divider</h5>
<p class="mb-0">Only the final percentages are recorded here.</p>
</div>
</Pane2>
</SplitView>
</div>
<div class="col-lg-4">
<div class="border rounded p-3 h-100 bg-body-tertiary">
<div class="fw-semibold mb-2">Resize Ended</div>
<div class="mb-2">Primary pane: <strong>@primaryPaneSize.ToString("0.##")%</strong></div>
<div>Secondary pane: <strong>@secondaryPaneSize.ToString("0.##")%</strong></div>
</div>
</div>
</div>
@code {
private double primaryPaneSize = 36;
private double secondaryPaneSize = 64;
private void HandleResizeEnded(SplitViewResizeEventArgs args)
{
primaryPaneSize = args.PrimaryPaneSize;
secondaryPaneSize = args.SecondaryPaneSize;
}
}Nested Layouts #
Files
SplitView.razor
<SplitView @bind-PrimaryPaneSize="paneSize">
<Pane1>...</Pane1>
<Pane2>...</Pane2>
</SplitView>Live Preview
Nested SplitView layouts are useful for IDEs, dashboards, and administration portals.
<SplitView Class="border rounded shadow-sm"
Style="height: 460px;"
PrimaryPaneSize="28"
MinimumPaneSize="18"
Color="SplitViewColor.Secondary">
<Pane1>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Explorer</div>
<h5 class="mb-3">Files</h5>
<div class="list-group list-group-flush">
<div class="list-group-item px-0">Pages</div>
<div class="list-group-item px-0">Components</div>
<div class="list-group-item px-0">Styles</div>
<div class="list-group-item px-0">Assets</div>
</div>
</div>
</Pane1>
<Pane2>
<SplitView Style="height: 100%;"
Orientation="SplitViewOrientation.Vertical"
PrimaryPaneSize="62"
MinimumPaneSize="20"
Color="SplitViewColor.Dark">
<Pane1>
<div class="h-100 p-4 bg-body">
<div class="small text-uppercase text-secondary mb-2">Editor</div>
<h5 class="mb-3">SplitView.razor</h5>
<pre class="mb-0 small bg-dark text-light rounded p-3 h-100 overflow-auto"><SplitView @@bind-PrimaryPaneSize="paneSize">
<Pane1>...</Pane1>
<Pane2>...</Pane2>
</SplitView></pre>
</div>
</Pane1>
<Pane2>
<div class="h-100 p-4 bg-body-tertiary">
<div class="small text-uppercase text-secondary mb-2">Preview</div>
<h5 class="mb-3">Live Preview</h5>
<p class="mb-0">Nested SplitView layouts are useful for IDEs, dashboards, and administration portals.</p>
</div>
</Pane2>
</SplitView>
</Pane2>
</SplitView>