@bundu/ui 0.8.0
(owner rulings of 1 and 2 November 2026; tracking issue
mzizi-registry#597).
What the floor is
Nothing readable is smaller than 14px, and nothing interactive has a hit region smaller than
49px. The numbers live in one place in the registry,
BUNDU_FLOOR in
lib/tokens/roles.source.ts; the token generators, the contract runner, the Rust evaluator
and the registry’s tests all read it. It replaces, in order, the 48px and 56px targets and 16px
body of the registry before 1 November 2026, and the 44px touch, 24px desktop and 15px desktop
body that followed for two days.
How a control keeps 49px on a desktop
A desktop control may be drawn smaller (28 to 40px) but keeps a 49px hit region. The token layer’shit-area rule gives every button, summary, [role="button"], [role="tab"],
[role="switch"] and any .hit-area element a transparent ::after of
max(100%, var(--target-floor)). --target-floor is 49px and no density layer lowers it.
The rule steps aside on purpose for an element that draws its own after: pseudo-element
(checkbox, switch, radio group, the tabs line variant), for menu and listbox rows (they take
min-height: var(--target-floor) instead), for a calendar day, and for an element with
overflow: hidden, which would clip it. Three consequences matter when you build:
- A native
input,selectortextareacannot carry a pseudo-element, so the field roles (h-field,h-field-sm) stay 49px drawn on a desktop. - A standalone link that is a target is drawn at 49px, or takes the
hit-areaclass. An inline link in running text is exempt, as in WCAG 2.5.8. - Where two covered controls sit closer than 49px apart their overlays overlap and the later sibling wins the overlap, so keep gaps from the spacing tokens.
Three layers, one floor
The layers are defined once in the token layer and emitted as media queries on the size variables. A component never branches on screen size.
Only display and heading sizes step down as screens grow. Body and secondary text never do. A
touchscreen laptop reports a coarse pointer, so the desktop layer does not apply to it.
Density is about visual size only: screen size is never used to guess network quality, and the
gaps between targets are spacing tokens that density does not change.
Contrast beside the floor
The floor’s contrast numbers are WCAG 2 minimums: 7:1 for body text, 4.5:1 for non-body text and 3:1 for UI parts. The registry’s token build fails when a default role is under its minimum, and the APCA bars still apply. Five button-label roles hold 4.5:1 rather than 7:1, an owner-confirmed exception:primary-foreground, brand-accent-foreground,
app-accent-foreground, sidebar-primary-foreground and destructive-foreground. The
thresholds, the reason for the exception and how to test a pairing are on
accessibility.
Migrating from the earlier sizes
“Earlier” is the registry’s 1 November 2026 sizes (4.21.0 to 4.22.x). Nothing changes for an app until it takes the new registry version or@bundu/ui 0.8.0.
In an app:
- Take the registry version (or
@bundu/uibuilt from it) and re-runpnpm tokens:syncor re-copymzizi-tokens-globals.css. - Replace
h-12,h-14andmin-h-[44px]on a control with a size role (h-control,h-field,min-h-touch-min). A drawn size under 49px is fine on a desktop for a button-like control, never for a field or a standalone link. - Replace any
text-[Npx]under 14 withtext-sm, and write body copy astext-body. - If a layout breaks and cannot move yet, set the legacy alias (below) and plan the move.
The legacy alias
To take the version and keep the earlier sizes for a while, put the attribute on the root element:text-xs and text-body follow the
same variables, so they step out with it.
One class name to avoid
Write body copy astext-body, not text-base. The token layer registers --text-base
(17px), but a theme that also defines a colour named base (--color-base) can make
text-base ambiguous. The registry has not yet decided how to settle it; text-body,
text-sm and text-xs work meanwhile.
What fails the build
The registry’sbundu-floor test fails when a default type step is under its floor in any
layer, when a floored size role is under 49px, when --target-floor is lowered or the
hit-area rule is gone, when a desktop control is drawn under 28px or a native field under
49px, when a copy of the floor disagrees with BUNDU_FLOOR, or when a registry component names
an arbitrary text size under 14px. The contract runner and the Rust evaluator fail a density
row whose interactive control has a hit region under 49px on either pointer. Rows that predate
the floor are pinned, so a new one cannot join them unseen; see
the Dashboard Standard’s density table.
The Bundu Order
The Bundu Order draws on biblical mathematical patterns and prime numbers (owner, 2 November 2026). This section states only what the registry’s code holds, in itsbrand-guidelines doctrine page.
- The unit is 7px (
--radius-unit). The radii are 4, 7, 12, 14 and 17px and a pill, and they do not change. - P7 and P17 are prime steps of the surface-elevation ladder (
surfaceis P7,raisedis P17), and the seven experimental colour families are a heptagon of hues offset 17 degrees. - The floors derive from the same numbers. Body text is 17px, a prime and Apple’s iOS default, on every device. Captions are 14px (2 × 7). Every control keeps a 49px hit region (7 × 7, above Apple’s 44 pt) and may be drawn down to 28px (4 × 7) at desktop density, never with a smaller hit region.
sizes-and-density.md
(the migration guide) and its content/doctrine/documentation/brand-guidelines.mdx.