Resizable
ui-resizable is a flex container for ui-resizable-panel elements separated by ui-resizable-handle elements.
Each panel's size is its share of the group. Dragging a handle, or focusing it and pressing the arrow keys,
moves size from one neighbouring panel to the other, never below either panel's min. The group is as wide as its
container. Give it a height in spacing units (or size its parent), and add variant="outline" for a border.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Resizable demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-medium {
width: min(100%, calc(var(--spacing) * 120));
}
.demo-tile {
display: grid;
place-items: center;
box-sizing: border-box;
height: 100%;
min-height: calc(var(--spacing) * 16);
padding: calc(var(--spacing) * 4);
border-radius: var(--radius-lg);
background: var(--muted);
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/resizable.html"></import-element>
<div class="demo-medium">
<ui-resizable variant="outline" height="48">
<ui-resizable-panel size="50">
<div class="demo-tile">One</div>
</ui-resizable-panel>
<ui-resizable-handle></ui-resizable-handle>
<ui-resizable-panel size="50">
<div class="demo-tile">Two</div>
</ui-resizable-panel>
</ui-resizable>
</div>
</body>
</html>Examples
Vertical
direction="vertical" stacks the panels. Drag the handle up and down, or use the Up and Down arrows.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Resizable demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-narrow {
width: min(100%, calc(var(--spacing) * 88));
}
.demo-tile {
display: grid;
place-items: center;
box-sizing: border-box;
height: 100%;
min-height: calc(var(--spacing) * 16);
padding: calc(var(--spacing) * 4);
border-radius: var(--radius-lg);
background: var(--muted);
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/resizable.html"></import-element>
<div class="demo-narrow">
<ui-resizable direction="vertical" variant="outline" height="64">
<ui-resizable-panel size="30">
<div class="demo-tile">Header</div>
</ui-resizable-panel>
<ui-resizable-handle></ui-resizable-handle>
<ui-resizable-panel size="70">
<div class="demo-tile">Content</div>
</ui-resizable-panel>
</ui-resizable>
</div>
</body>
</html>Visible grip
Add handle to a handle to draw a grip on it, which makes the drag target easier to see.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Resizable demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-medium {
width: min(100%, calc(var(--spacing) * 120));
}
.demo-tile {
display: grid;
place-items: center;
box-sizing: border-box;
height: 100%;
min-height: calc(var(--spacing) * 16);
padding: calc(var(--spacing) * 4);
border-radius: var(--radius-lg);
background: var(--muted);
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/resizable.html"></import-element>
<div class="demo-medium">
<ui-resizable variant="outline" height="40">
<ui-resizable-panel size="25" min="15">
<div class="demo-tile">Sidebar</div>
</ui-resizable-panel>
<ui-resizable-handle handle></ui-resizable-handle>
<ui-resizable-panel size="75" min="40">
<div class="demo-tile">Content</div>
</ui-resizable-panel>
</ui-resizable>
</div>
</body>
</html>Nested groups
A panel can hold another group in the other direction.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Resizable demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-medium {
width: min(100%, calc(var(--spacing) * 120));
}
.demo-tile {
display: grid;
place-items: center;
box-sizing: border-box;
height: 100%;
min-height: calc(var(--spacing) * 16);
padding: calc(var(--spacing) * 4);
border-radius: var(--radius-lg);
background: var(--muted);
font-size: var(--text-sm);
font-weight: var(--font-weight-medium);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/resizable.html"></import-element>
<div class="demo-medium">
<ui-resizable variant="outline" height="56">
<ui-resizable-panel size="40">
<div class="demo-tile">One</div>
</ui-resizable-panel>
<ui-resizable-handle handle></ui-resizable-handle>
<ui-resizable-panel size="60">
<ui-resizable direction="vertical">
<ui-resizable-panel size="25">
<div class="demo-tile">Two</div>
</ui-resizable-panel>
<ui-resizable-handle handle></ui-resizable-handle>
<ui-resizable-panel size="75">
<div class="demo-tile">Three</div>
</ui-resizable-panel>
</ui-resizable>
</ui-resizable-panel>
</ui-resizable>
</div>
</body>
</html>API
Attributes
ui-resizable
| Attribute | Type | Default | Description |
|---|---|---|---|
direction |
"horizontal" | "vertical" |
"horizontal" |
Lays the panels out in a row or a column. Handles read it when they connect. |
height |
number | none | Height in spacing units, so height="48" is calc(var(--spacing) * 48). Without it the group fills its parent's height. |
variant |
"default" | "outline" |
"default" |
outline adds a 1px border and var(--radius-lg) corners. |
ui-resizable-panel
| Attribute | Type | Default | Description |
|---|---|---|---|
size |
number | 50 |
The panel's share of the group, used as its flex-grow. Between 0 and 100. Make the sizes in a group add up to 100 so they read as percentages. Updated while resizing. |
min |
number | 10 |
The smallest size a handle can shrink the panel to. At least 0. |
ui-resizable-handle
| Attribute | Type | Default | Description |
|---|---|---|---|
handle |
boolean | false |
Shows a visible grip in the middle of the handle. |
Properties and methods
ui-resizable-panel exposes size and min as properties. Set size from script to resize a panel. The handles
read both properties from the panels on either side.
Parts
| Part | Slot | Renders |
|---|---|---|
ui-resizable-panel |
(default) | One panel. Its content scrolls when it overflows. |
ui-resizable-handle |
(default) | A separator between two panels that resizes them. |
Panels and handles alternate in the default slot of ui-resizable. The default slot of a panel takes any content,
including another ui-resizable.
CSS parts
| Part | Element | Description |
|---|---|---|
grip |
ui-resizable-handle |
The grip shown with the handle attribute. |
CSS states and custom properties
ui-resizable-handle:state(vertical)matches handles in a vertical group, which are horizontal lines.ui-resizable-panelapplies its size through the reactive custom property--attr-size.
Accessibility
- Each handle has
role="separator",aria-orientation(verticalbetween side-by-side panels,horizontalbetween stacked panels),aria-valuemin="0"andaria-valuemax="100". After a resize,aria-valuenowholds the size of the panel before the handle. - Handles are in the Tab order. Left and Up arrows shrink the panel before the handle by 5, Right and Down arrows
grow it by 5, within both panels'
min. - Dragging uses pointer capture, so the drag continues when the pointer leaves the handle.
- Give a handle an
aria-labelthat says what it resizes, for examplearia-label="Resize sidebar".