Skip to main content
The spacing floor is the part of the Bundu floor that sets minimums for space rather than size: padding, gaps and line height that nothing can go under, even a component that sets no padding at all. It shipped in registry 4.24.0 (4 November 2026), on the 7px unit the rest of the floor uses (owner ruling of 4 November 2026; tracking issue mzizi-registry#617).

The five floors

The numbers live in one place in the registry, BUNDU_FLOOR.spacing in lib/tokens/roles.source.ts. The registry serves them as the same five numbers everywhere (see one set of numbers). No brand pack and no density layer lowers a floor; the one exception is the legacy opt-out, which steps out of it.

Why

The reasons are the Bundu floor’s: older users, people reading outdoors in glare, people on small and cheap phones, and the mis-taps that cramped controls cause. A control with its neighbour 2px away is easy to hit by mistake, text that touches its container edge is hard to find in glare, and a line height under 1.5 is harder to track for anyone who reads slowly or with low vision. The spacing floor is design intent backed by the registry’s tests (below), not a measured result: no pilot or user study on this site shows its effect.

How a component meets it

The token layer carries the floor, so a component that sets nothing already meets it.
  • The variables --inset-floor, --gap-floor and --leading-floor are in :root of mzizi-tokens-globals.css. They are also registered as fixed size roles, so the platform token files carry 14 and 7 as they carry 49.
  • The base layer enforces defaults for an element that sets nothing: padding-inline: var(--inset-floor) on a bare button, select, textarea or text input; padding: var(--inset-floor) on a bare text surface (a native dialog, a [popover], an alert, a tooltip, a card with no structured children); gap: var(--gap-floor) on a list, group, toolbar or tablist; and line-height: max(var(--lh-body), var(--leading-floor)) on body.
  • It steps aside, on purpose, for an icon-only button, an empty element, a fixed square (size-*), a calendar day, the native checkbox, radio, range, colour and file inputs, and a card whose padding lives on its card-header and card-content children (padding both would pad twice).
  • A utility is your own value. p-3 or gap-1 on the element wins over the base layer, even when it is under the floor, so an explicit value is held to the floor only by a check you run (the CLI below); the registry’s contract tests are not yet on main. Write p-inset-floor, px-inset-floor or gap-gap-floor to take the floor itself.
  • A control’s block axis is held by its height. 14px of block padding does not fit a control drawn at 28px, so for a control the inset floor is the inline axis, and for a surface it is both axes.
  • The 7px gap is measured between visible edges. The registry says hit regions may touch but not overlap. The 49px hit-area overlay may reach into the gap, though: where two covered controls sit closer than 49px apart their overlays overlap and the later sibling wins the overlap, so keep gaps at the floor or above.

How it is enforced

What is on registry main (4.24.0) and what is still to come are different, so the table separates them. The registry’s 4.24.0 changelog says the component audit, contract and Rust parity, the geometry guard and the lint-style tests “follow in their own pull request”.

In an app: the CLI

@nyuchi/mzizi-cli 0.8.0 adds mzizi check [path...], which enforces the floor over your source. It is merged on the agent-tools staging branch and ships with that package’s next release. As of 4 November 2026 the latest version on npm is 0.7.0, which has no check command; run npx @nyuchi/mzizi-cli --version to see what you get.
It is offline and reads the values written in your source. It does not resolve var() or calc(), it does not check vertical padding other than zero, and a tight line height on a display heading needs an exception comment (below). Those limits are the CLI’s own, stated in its README.

The exception comment

A violation that is deliberate carries a comment with a reason, on the same line or the line before (in CSS, or the comment syntax of the language you are in):
A comment with no reason is not an exception. Exceptions are listed in the report, so a reviewer can see each one. The first 20 lines of a file take a -file form that covers the whole file.

The legacy opt-out

data-mzizi-sizes="legacy" on the root element, the alias the Bundu floor describes, also sets --inset-floor, --gap-floor and --leading-floor to 0, 0 and 1. The registry describes the base-layer rules above as a no-op then. A rule that still reads a variable set to 0 applies 0, so look at your native dialogs and popovers after you opt out. It steps out of the floor. Use it only to take the registry version before you have moved your layouts, and remove it as soon as you have.

One set of numbers

The floor is read from the registry, not typed in each place: If a surface disagrees with BUNDU_FLOOR, the surface is wrong: change it upstream in the registry.

Sources

The registry’s sizes-and-density.md holds the rule and its tests, and mzizi-registry#617 the owner’s ruling and the list of surfaces it lands on.