Domphy

Row

Apply the row patch to any block element to lay out its children as a horizontal flex row with spacing between them, vertically centered by default — the general-purpose primitive for icon+label rows, field rows, and button groups, instead of hand-rolling display: flex; alignItems: center; gap: .... toolbar is a semantic alias of this same shape for headers/nav bars; reach for row directly when you need justify/wrap/a non-center align.

Props

PropTypeDefaultDescription
gapnumber4Spacing multiplier for gap between items. Final gap = themeSpacing(density × gap); at default density (1.5), gap 41.5em.
align"flex-start" | "center" | "flex-end" | "stretch" | "baseline""center"Cross-axis alignment (alignItems).
justify"flex-start" | "center" | "flex-end" | "space-between" | "space-around" | "space-evenly"unsetMain-axis distribution (justifyContent). Left unset by default (flex's own default, flex-start).
wrapbooleanfalseAllow items to wrap onto multiple lines (flexWrap: "wrap").

Example

import { row } from "@domphy/ui";

const Field = {
  div: [{ label: "Name" }, { input: null, placeholder: "Jane" }],
  $: [row({ justify: "space-between" })],
};
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:

  1. Patch props. Each patch exposes a small, stable set of props—typically fewer than five. Lowest friction.
  2. Context attributes. Use dataTone, dataSize, and dataDensity on a container to shift tone, size, or density for an entire subtree without touching individual elements.
  3. Inline override. Native-wins merge strategy: any property set directly on the element overrides the patch value.
  4. 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 * U

Base density d = 1.5:

Uw=0w=1w=2w=3
height (n = 1)691215
paddingBlock01.534.5
paddingInline34.564.5
radius01.534.5

Tone - K = N / 2 where N is the palette length. For N = 18, K = 9.

RoleShiftn=0
Backgroundparent +/- n0
Textbg + K6
Borderbg + K/23
Hoverbg + 2K/34
Selected / Focusabove +/- K/32-4

State shift range: K/3 <= delta <= 2K/3.

import type { PartialElement } from "@domphy/core";
import { themeDensity, themeSpacing } from "@domphy/theme";
import type { FlexAlign } from "./stack.js";

type FlexJustify =
  | "flex-start"
  | "center"
  | "flex-end"
  | "space-between"
  | "space-around"
  | "space-evenly";

/**
 * A horizontal flex row with spacing between children, vertically centered by
 * default. The general-purpose primitive for icon+label rows, field rows,
 * and button groups — instead of hand-rolling `display: flex; alignItems:
 * center; gap: ...`. `toolbar()` is a semantic alias of this same shape for
 * headers/nav bars. Styles the host only; apply to any block element.
 *
 * @param props.gap - Spacing multiplier for gap between items (default 4 = 1em at density 1).
 * @param props.align - Cross-axis alignment (`alignItems`). Defaults to `"center"`.
 * @param props.justify - Main-axis distribution (`justifyContent`). Unset by default (flex-start).
 * @param props.wrap - Allow items to wrap onto multiple lines. Defaults to `false`.
 * @example { div: [{ span: "Icon" }, { span: "Label" }], $: [row()] }
 * @example { div: [...], $: [row({ justify: "space-between", wrap: true })] }
 */
function row(
  props: {
    gap?: number;
    align?: FlexAlign;
    justify?: FlexJustify;
    wrap?: boolean;
  } = {},
): PartialElement {
  const { gap = 4, align = "center", justify, wrap = false } = props;
  return {
    style: {
      display: "flex",
      alignItems: align,
      gap: (listener) => themeSpacing(themeDensity(listener) * gap),
      ...(justify ? { justifyContent: justify } : {}),
      ...(wrap ? { flexWrap: "wrap" } : {}),
    },
  };
}

export { row };
export type { FlexJustify };