Panel Section
Apply the panelSection patch to any block element for the padded-section chrome common to side-panel and inspector UIs: density-aware padding on all sides, with an optional bottom divider for sections stacked one after another. It's a thin wrapper — it does not impose flex layout on its children, so pair it with stack or row for that.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
padding | number | 4 | Spacing multiplier for padding on all sides. Final padding = themeSpacing(density × padding); at default density (1.5), padding 4 ≈ 1.5em. |
divider | boolean | false | Adds a bottom border, for sections stacked one after another. |
color | ValueOrState<ThemeColor> | "neutral" | Theme color tone for the divider border. |
Example
import { panelSection, stack } from "@domphy/ui";
const Sidebar = {
div: [
{ div: [{ h4: "Parameters" }, { p: "..." }], $: [stack({ gap: 1 }), panelSection({ divider: true })] },
{ div: [{ h4: "Operations" }, { p: "..." }], $: [stack({ gap: 1 }), panelSection()] },
],
$: [stack({ gap: 0 })],
};Customization
Must see the source of patch at the bottom of each patch page to understand the structure then code it still code as html native element.
There are four levels of customization, in increasing order of effort:
- Patch props. Each patch exposes a small, stable set of props—typically fewer than five. Lowest friction.
- Context attributes. Use
dataTone,dataSize, anddataDensityon a container to shift tone, size, or density for an entire subtree without touching individual elements. - Inline override. Native-wins merge strategy: any property set directly on the element overrides the patch value.
- Create a variant. Clone a similar patch and edit it. Use this only when you need a reusable custom version.
Formulas
Unit - U = fontSize / 4 - convert final values with themeSpacing(n).
Size - n = intrinsic text lines, w = wrapping level, d = density factor:
height = (n * 6 + 2 * d * w) * U
paddingBlock = d * w * U
paddingInline = ceil(3 / w) * d * w * U
radius = d * w * UBase density d = 1.5:
| U | w=0 | w=1 | w=2 | w=3 |
|---|---|---|---|---|
height (n = 1) | 6 | 9 | 12 | 15 |
| paddingBlock | 0 | 1.5 | 3 | 4.5 |
| paddingInline | 3 | 4.5 | 6 | 4.5 |
| radius | 0 | 1.5 | 3 | 4.5 |
Tone - K = N / 2 where N is the palette length. For N = 18, K = 9.
| Role | Shift | n=0 |
|---|---|---|
| Background | parent +/- n | 0 |
| Text | bg + K | 6 |
| Border | bg + K/2 | 3 |
| Hover | bg + 2K/3 | 4 |
| Selected / Focus | above +/- K/3 | 2-4 |
State shift range: K/3 <= delta <= 2K/3.
import { type PartialElement, toState, type ValueOrState } from "@domphy/core";
import {
type ThemeColor,
themeColor,
themeDensity,
themeSpacing,
} from "@domphy/theme";
/**
* A padded section for side-panel/inspector UIs — density-aware padding on
* all sides, with an optional bottom divider for sections stacked one after
* another. A thin wrapper: it does not impose flex layout on its children —
* pair it with `stack()` or `row()` for that. No host-tag check; apply to
* any block element.
*
* @param props.padding - Spacing multiplier for padding on all sides (default 4 = 1em at density 1).
* @param props.divider - Adds a bottom border, for sections stacked one after another. Defaults to `false`.
* @param props.color - Theme color tone for the divider border. Defaults to `"neutral"`.
* @example { div: [{ h3: "Parameters" }, { p: "..." }], $: [panelSection()] }
* @example
* { div: [
* { div: "Section A", $: [panelSection({ divider: true })] },
* { div: "Section B", $: [panelSection()] },
* ], $: [stack({ gap: 0 })] }
*/
function panelSection(
props: {
padding?: number;
divider?: boolean;
color?: ValueOrState<ThemeColor>;
} = {},
): PartialElement {
const { padding = 4, divider = false } = props;
const color = toState(props.color ?? "neutral", "color");
return {
style: {
padding: (listener) => themeSpacing(themeDensity(listener) * padding),
...(divider
? {
borderBottom: (listener) =>
`1px solid ${themeColor(listener, "border", color.get(listener))}`,
}
: {}),
},
};
}
export { panelSection };