2021-12-22 23:32:27 +00:00
# Split Panel
[component-header:sl-split-panel]
2021-12-23 16:23:14 +00:00
Split panels display two adjacent panels, allowing the user to reposition them.
2021-12-22 23:32:27 +00:00
```html preview
< sl-split-panel >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-22 23:32:27 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
2021-12-22 23:32:27 +00:00
< / div >
< / sl-split-panel >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel } from '@shoelace-style/shoelace/dist/react';
const App = () => (
< SlSplitPanel >
< div slot = "start" style = {{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
Start
< / div >
< div slot = "end" style = {{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
End
< / div >
< / SlSplitPanel >
);
```
2021-12-22 23:32:27 +00:00
## Examples
### Initial Position
2021-12-30 23:14:07 +00:00
To set the initial position, use the `position` attribute. If no position is provided, it will default to 50% of the available space.
2021-12-22 23:32:27 +00:00
```html preview
2021-12-30 23:14:07 +00:00
< sl-split-panel position = "75" >
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
< / div >
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
< / div >
< / sl-split-panel >
```
### Initial Position in Pixels
To set the intial position in pixels instead of a percentage, use the `position-in-pixels` attribute.
```html preview
< sl-split-panel position-in-pixels = "150" >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-22 23:32:27 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
2021-12-22 23:32:27 +00:00
< / div >
< / sl-split-panel >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel } from '@shoelace-style/shoelace/dist/react';
const App = () => (
< SlSplitPanel position = "200" >
< div
slot="start"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div
slot="end"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
End
< / div >
< / SlSplitPanel >
);
```
2021-12-22 23:32:27 +00:00
### Vertical
2021-12-23 16:23:14 +00:00
Add the `vertical` attribute to render the split panel in a vertical orientation where the start and end panels are stacked. You also need to set a height when using the vertical orientation.
2021-12-22 23:32:27 +00:00
```html preview
< sl-split-panel vertical style = "height: 400px;" >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 100%; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-22 23:32:27 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 100%; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
2021-12-22 23:32:27 +00:00
< / div >
< / sl-split-panel >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel } from '@shoelace-style/shoelace/dist/react';
const App = () => (
< SlSplitPanel vertical style = {{ height: ' 400px ' } } >
< div
slot="start"
style={{
height: '100%',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div
slot="end"
style={{
height: '100%',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
End
< / div >
< / SlSplitPanel >
);
```
2021-12-22 23:32:27 +00:00
### Snapping
2021-12-23 16:23:14 +00:00
To snap panels at specific positions while dragging, add the `snap` attribute with one or more space-separated values. Values must be in pixels or percentages. For example, to snap the panel at `100px` and `50%` , use `snap="100px 50%"` . You can also customize how close the divider must be before snapping with the `snap-threshold` attribute.
2021-12-22 23:32:27 +00:00
```html preview
< div class = "split-panel-snapping" >
< sl-split-panel snap = "100px 50%" >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-22 23:32:27 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
2021-12-22 23:32:27 +00:00
< / div >
< / sl-split-panel >
< div class = "split-panel-snapping-dots" > < / div >
< / div >
< style >
.split-panel-snapping {
position: relative;
}
.split-panel-snapping-dots::before,
.split-panel-snapping-dots::after {
content: '';
position: absolute;
bottom: -12px;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--sl-color-neutral-400);
transform: translateX(-3px);
}
.split-panel-snapping-dots::before {
left: 100px;
}
.split-panel-snapping-dots::after {
left: 50%;
}
< / style >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel } from '@shoelace-style/shoelace/dist/react';
const css = `
.split-panel-snapping {
position: relative;
}
.split-panel-snapping-dots::before,
.split-panel-snapping-dots::after {
content: '';
position: absolute;
bottom: -12px;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--sl-color-neutral-400);
transform: translateX(-3px);
}
.split-panel-snapping-dots::before {
left: 100px;
}
.split-panel-snapping-dots::after {
left: 50%;
}
`;
const App = () => (
< >
< div className = "split-panel-snapping" >
< SlSplitPanel snap = "100px 50%" >
< div
slot="start"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div
slot="end"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
End
< / div >
< / SlSplitPanel >
< div className = "split-panel-snapping-dots" / >
< / div >
< style > { c s s } < / style >
< />
);
```
2021-12-22 23:32:27 +00:00
### Disabled
2021-12-30 23:14:07 +00:00
Add the `disabled` attribute to prevent the divider from being repositioned.
2021-12-22 23:32:27 +00:00
```html preview
< sl-split-panel disabled >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-22 23:32:27 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
2021-12-22 23:32:27 +00:00
< / div >
< / sl-split-panel >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel } from '@shoelace-style/shoelace/dist/react';
const App = () => (
< SlSplitPanel disabled >
< div
slot="start"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div
slot="end"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
End
< / div >
< / SlSplitPanel >
);
```
2021-12-23 13:24:44 +00:00
### Setting the Primary Panel
2021-12-22 23:32:27 +00:00
2021-12-23 16:23:14 +00:00
By default, both panels will grow or shrink proportionally when the host element is resized. If a primary panel is designated, it will maintain its size and the secondary panel will grow or shrink to fit the remaining space. You can set the primary panel to `start` or `end` using the `primary` attribute.
2021-12-23 15:07:37 +00:00
2021-12-23 16:23:14 +00:00
Try resizing the example below with each option and notice how the panels respond.
2021-12-22 23:32:27 +00:00
```html preview
2021-12-23 13:24:44 +00:00
< div class = "split-panel-primary" >
2021-12-23 16:23:14 +00:00
< sl-split-panel >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-22 23:32:27 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
2021-12-22 23:32:27 +00:00
< / div >
< / sl-split-panel >
2021-12-23 16:23:14 +00:00
< sl-select label = "Primary Panel" value = "" style = "max-width: 200px; margin-top: 1rem;" >
< sl-menu-item value = "" > None< / sl-menu-item >
2021-12-22 23:32:27 +00:00
< sl-menu-item value = "start" > Start< / sl-menu-item >
< sl-menu-item value = "end" > End< / sl-menu-item >
< / sl-select >
< / div >
< script >
2021-12-23 13:24:44 +00:00
const container = document.querySelector('.split-panel-primary');
2021-12-22 23:32:27 +00:00
const splitPanel = container.querySelector('sl-split-panel');
const select = container.querySelector('sl-select');
2021-12-23 13:24:44 +00:00
select.addEventListener('sl-change', () => splitPanel.primary = select.value);
2021-12-22 23:32:27 +00:00
< / script >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { useState } from 'react';
import { SlSplitPanel, SlSelect, SlMenuItem } from '@shoelace-style/shoelace/dist/react';
const App = () => {
const [primary, setPrimary] = useState('');
return (
< >
< SlSplitPanel primary = {primary} >
< div
slot="start"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div
slot="end"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
End
< / div >
< / SlSplitPanel >
< SlSelect
label="Primary Panel"
value={primary}
style={{ maxWidth: '200px', marginTop: '1rem' }}
onSlChange={event => setPrimary(event.target.value)}
>
< SlMenuItem value = "" > None< / SlMenuItem >
< SlMenuItem value = "start" > Start< / SlMenuItem >
< SlMenuItem value = "end" > End< / SlMenuItem >
< / SlSelect >
< />
);
};
```
2021-12-23 15:07:37 +00:00
### Min & Max
2021-12-30 23:14:07 +00:00
To set a minimum or maximum size of the primary panel, use the `--min` and `--max` custom properties. Since the secondary panel is flexible, size constraints can only be applied to the primary panel. If no primary panel is designated, these constraints will be applied to the `start` panel.
2021-12-23 16:39:25 +00:00
2021-12-30 23:14:07 +00:00
This examples demonstrates how you can ensure both panels are at least 150px using `--min` , `--max` , and the `calc()` function.
2021-12-23 15:07:37 +00:00
```html preview
< sl-split-panel style = "--min: 150px; --max: calc(100% - 150px);" >
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
< / div >
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
< / div >
< / sl-split-panel >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel } from '@shoelace-style/shoelace/dist/react';
const App = () => (
< SlSplitPanel style = {{ ' --min ' : ' 150px ' , ' --max ' : ' calc ( 100 % - 150px ) ' } } >
< div
slot="start"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div
slot="end"
style={{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
End
< / div >
< / SlSplitPanel >
);
```
2021-12-22 23:32:27 +00:00
### Nested Split Panels
2021-12-23 16:23:14 +00:00
Create complex layouts that can be repositioned independently by nesting split panels.
2021-12-22 23:32:27 +00:00
```html preview
< sl-split-panel >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 400px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-22 23:32:27 +00:00
< / div >
< div slot = "end" >
< sl-split-panel vertical style = "height: 400px;" >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 100%; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Top
2021-12-22 23:32:27 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 100%; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Bottom
2021-12-22 23:32:27 +00:00
< / div >
< / sl-split-panel >
< / div >
< / sl-split-panel >
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel } from '@shoelace-style/shoelace/dist/react';
const App = () => (
< SlSplitPanel >
< div
slot="start"
style={{
height: '400px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div slot = "end" >
< SlSplitPanel vertical style = {{ height: ' 400px ' } } >
< div
slot="start"
style={{
height: '100%',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
Start
< / div >
< div
slot="end"
style={{
height: '100%',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
End
< / div >
< / SlSplitPanel >
< / div >
< / SlSplitPanel >
);
```
2021-12-22 23:32:27 +00:00
### Customizing the Divider
2021-12-23 15:07:37 +00:00
You can target the `divider` part to apply CSS properties to the divider. To add a handle, slot an icon or another element into the `handle` slot. When customizing the divider, make sure to think about focus styles for keyboard users.
2021-12-22 23:32:27 +00:00
```html preview
2021-12-27 19:04:20 +00:00
< sl-split-panel style = "--divider-width: 20px;" >
< sl-icon slot = "handle" name = "grip-vertical" > < / sl-icon >
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
< / div >
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
< / div >
< / sl-split-panel >
```
```jsx react
import { SlSplitPanel, SlIcon } from '@shoelace-style/shoelace/dist/react';
const App = () => (
< SlSplitPanel style = {{ ' --divider-width ' : ' 20px ' } } >
< SlIcon slot = "handle" name = "grip-vertical" / >
< div slot = "start" style = {{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
2021-12-23 15:07:37 +00:00
Start
< / div >
2021-12-27 19:04:20 +00:00
< div slot = "end" style = {{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
2021-12-23 15:07:37 +00:00
End
< / div >
2021-12-27 19:04:20 +00:00
< / SlSplitPanel >
);
2021-12-23 15:07:37 +00:00
```
2021-12-23 15:27:05 +00:00
Here's a more elaborate example that changes the divider's color and width and adds a styled handle.
2021-12-23 15:07:37 +00:00
```html preview
< div class = "split-panel-handle" >
2021-12-23 00:07:16 +00:00
< sl-split-panel >
< sl-icon slot = "handle" name = "grip-vertical" > < / sl-icon >
2021-12-23 15:07:37 +00:00
< div slot = "start" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
Start
2021-12-23 00:07:16 +00:00
< / div >
2021-12-23 15:07:37 +00:00
< div slot = "end" style = "height: 200px; background: var(--sl-color-neutral-50); display: flex; align-items: center; justify-content: center;" >
End
2021-12-23 00:07:16 +00:00
< / div >
< / sl-split-panel >
< / div >
< style >
2021-12-23 15:07:37 +00:00
.split-panel-handle sl-split-panel {
--divider-width: 2px;
}
.split-panel-handle sl-split-panel::part(divider) {
2021-12-23 00:07:16 +00:00
background-color: var(--sl-color-pink-600);
}
2021-12-23 15:07:37 +00:00
.split-panel-handle sl-icon {
2021-12-23 00:07:16 +00:00
position: absolute;
border-radius: var(--sl-border-radius-small);
background: var(--sl-color-pink-600);
color: var(--sl-color-neutral-0);
padding: .5rem .125rem;
}
2021-12-23 15:07:37 +00:00
.split-panel-handle sl-split-panel::part(divider):focus-visible {
2021-12-23 00:07:16 +00:00
background-color: var(--sl-color-primary-600);
}
2021-12-23 15:07:37 +00:00
.split-panel-handle sl-split-panel:focus-within sl-icon {
2021-12-23 00:07:16 +00:00
background-color: var(--sl-color-primary-600);
color: var(--sl-color-neutral-0);
}
< / style >
2021-12-22 23:32:27 +00:00
```
2021-12-27 19:04:20 +00:00
```jsx react
import { SlSplitPanel, SlIcon } from '@shoelace-style/shoelace/dist/react';
const css = `
.split-panel-handle sl-split-panel {
--divider-width: 2px;
}
.split-panel-handle sl-split-panel::part(divider) {
background-color: var(--sl-color-pink-600);
}
.split-panel-handle sl-icon {
position: absolute;
border-radius: var(--sl-border-radius-small);
background: var(--sl-color-pink-600);
color: var(--sl-color-neutral-0);
padding: .5rem .125rem;
}
.split-panel-handle sl-split-panel::part(divider):focus-visible {
background-color: var(--sl-color-primary-600);
}
.split-panel-handle sl-split-panel:focus-within sl-icon {
background-color: var(--sl-color-primary-600);
color: var(--sl-color-neutral-0);
}
`;
const App = () => (
< >
< div className = "split-panel-handle" >
< SlSplitPanel >
< SlIcon slot = "handle" name = "grip-vertical" / >
< div slot = "start" style = {{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
Start
< / div >
< div slot = "end" style = {{
height: '200px',
background: 'var(--sl-color-neutral-50)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}>
End
< / div >
< / SlSplitPanel >
< / div >
< style > { c s s } < / style >
< />
);
```
2021-12-22 23:32:27 +00:00
[component-metadata:sl-split-panel]