with one click
heimdall-layout
Heimdall component guide for Layout: Panel, SplitPane
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Heimdall component guide for Layout: Panel, SplitPane
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Heimdall component guide for Charts: Sparkline, LineChart, BarChart, BarV, BarH, StackedBar, Donut, PieChart, Heatmap, StatusTimeline, ProgressBar, MetricRow
Heimdall component guide for Chat: ChatMessage, ToolBlock, ThinkingBlock, ChatDivider, ChatSuggestions, ChatComposer, ChatContainer
Heimdall component guide for Data Display: StatTile, StatGrid, Table, KVGrid, InspectorPanel
Heimdall component guide for Graph: GraphCanvas, GraphNode, GraphEdge, GraphInspector, TopologyNode, HierarchyRow, HierarchyTree
Heimdall component guide for Inputs: TextInput, TextArea, NumberInput, Select, TriState, Field, FilterDropdown, EntityPicker, KeyValueEditor, OrderedList, RelationshipBuilder
Heimdall component guide for Navigation: NavItem, Sidebar, Topbar, TabBar
| name | heimdall-layout |
| description | Heimdall component guide for Layout: Panel, SplitPane |
Import all components from @tinkermonkey/heimdall-ui. Import the CSS once at your app entry point:
import '@tinkermonkey/heimdall-ui/css'
Bordered content card with optional title, subtitle, header action slot, and footer.
import { Panel } from '@tinkermonkey/heimdall-ui'
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Panel header title |
subtitle | string | — | Secondary line in header |
headerAction | ReactNode | — | Trailing slot in header row |
footer | ReactNode | — | Footer slot with top border |
bordered | boolean | true | Show 1px outer border |
noPadding | boolean | false | Remove body padding for edge-to-edge content |
children | ReactNode | — | Panel body |
...HTMLAttributes | Standard div attributes |
// Minimal
<Panel title="Schema classes">
<p>Panel body content.</p>
</Panel>
// With subtitle, header action, and footer
<Panel
title="Import data"
subtitle="428 individuals · last synced 2m ago"
headerAction={
<Button variant="ghost" size="sm">
<Icon name="reload" size={14} />
</Button>
}
footer={
<div className="flex justify-end gap-2">
<Button variant="ghost" size="sm">Cancel</Button>
<Button variant="primary" size="sm">Import</Button>
</div>
}
>
{/* form content */}
</Panel>
// No padding for lists with their own dividers
<Panel title="Recent runs" noPadding>
{runs.map(run => (
<div key={run.id} className="px-4 py-2 border-b border-canvas">
{run.name}
</div>
))}
</Panel>
// No border (inside another container)
<Panel bordered={false} title="Embedded panel">
{/* content */}
</Panel>
title, subtitle, or headerAction is provided — no empty header divchildren is non-null — falsy values like 0 or false suppress the bodynoPadding affects only the body div; header and footer always have their own paddingResizable two-pane layout with mouse drag, keyboard navigation, and controlled/uncontrolled modes.
import { SplitPane } from '@tinkermonkey/heimdall-ui'
| Prop | Type | Default | Description |
|---|---|---|---|
first | ReactNode | required | Content for the first (left/top) pane |
second | ReactNode | required | Content for the second (right/bottom) pane |
direction | 'horizontal' | 'vertical' | 'horizontal' | Split orientation |
initialSplitPercent | number | 50 | Starting split position 0–100 (uncontrolled only) |
splitPercent | number | — | Controlled split position 0–100 |
onSplitChange | (percent: number) => void | — | Called when divider moves |
minSize | number | 200 | Minimum first-pane size in pixels |
maxSize | number | 800 | Maximum first-pane size in pixels |
dividerLabel | string | — | ARIA label for the divider |
...HTMLAttributes | Standard div attributes |
// Uncontrolled horizontal split
<SplitPane
direction="horizontal"
initialSplitPercent={40}
first={<div>Left pane</div>}
second={<div>Right pane</div>}
/>
// Controlled with constraints
const [split, setSplit] = useState(65)
<SplitPane
direction="horizontal"
splitPercent={split}
onSplitChange={setSplit}
minSize={200}
maxSize={900}
dividerLabel="Resize graph / inspector"
first={<GraphCanvas ... />}
second={<InspectorPanel ... />}
style={{ height: '100%' }}
/>
// Vertical split
<SplitPane
direction="vertical"
initialSplitPercent={60}
first={<div>Top pane</div>}
second={<div>Bottom pane</div>}
style={{ height: '500px' }}
/>
height: 100% or fixed-height containerminSize and maxSize are in pixels, but are clamped to percentages based on the container's current size at drag time — the effective percentage range changes as the viewport resizessecond pane always gets 100 - splitPercent percent; you cannot control both panes independentlydocument during drag, so dragging outside the container works correctly