The design language
This framework is a design philosophy for enterprise software first and a stylesheet second. The philosophy fits in one question — not "how can this look better?" but "what can I remove so the essential thing becomes obvious?" — and six principles below turn that question into rules a screen either follows or doesn't. Components emerge from the principles, never the other way around.
Design the decision, not the screen
Every screen exists to serve one decision its user must make. "The payroll manager needs to know whether payroll is safe to release" is a design brief; "we need a payroll screen" is not. The system may run fifty validations — the user reads Ready · 428 employees · 2 exceptions. Complexity lives under the interface, never in the user's mental model.
Every screen must answer, in order: what is this → what should I look at → what should I do. And a screen is one step of a journey (request → validation → exception → resolution → approval → execution → confirmation) — a beautiful screen inside a terrible workflow is still a bad product, so each screen's exit lands the user at the next decision with their context intact. The pattern pages are built this way: each opens with who uses it and what "done" looks like, before any markup.
The six rules
| Area | Principle | Where the framework enforces it |
|---|---|---|
| Hierarchy | One primary action per screen; secondary actions subordinate; destructive actions require explicit intent. | One plain bo-btn
per screen — everything else takes --secondary,
--ghost, or --danger-ghost. Measured, not
aspirational (live DOM at rest, all 21 pattern pages,
2026-08-21): every screen shows ≤1 visible primary action —
the wizard's Next/Submit pair is never both visible, the grid's
per-row Saves stay hidden until a row is dirty, and
master-detail's two demos (panel and dialog) carry one each. |
| Typography | Large = meaning, medium = context, small = supporting information. Size IS the hierarchy. | The type-scale tokens — components consume the scale, never free-pick sizes; density remaps one tier and every component follows. |
| Colour | Neutral by default. Colour communicates state — never decoration. | Semantic tones only (danger/warning/success), each
AA-contrast-gated in both themes at build time, and every colour
signal is two-channel: a visible non-colour cue plus a programmatic
one, so meaning never rides on hue alone. See
the accessibility
model and conditional
cell tone — the tone repeats a meaning already present in text. |
| Spacing | Consistent rhythm. Whitespace separates concepts; proximity groups related things. | The spacing scale in design
tokens plus layout primitives (bo-cluster,
bo-stack, bo-grid) that carry the rhythm —
pages compose primitives instead of hand-tuning margins. |
| Interaction | Direct manipulation; avoid needless dialogs; preserve context; immediate feedback. | Inline row editing over modal forms
(data-row-edit), errors
that re-render in place with the user's work intact
(concurrency &
conflicts), and focus restored across swaps so a keyboard user
is never dumped on <body>. |
| Content | Human language. Explain the consequence, not the mechanism. | Processing Status: 04 is refused; "Ready to
release" with detail underneath is the shape. Status strings name
meanings, technology stays invisible — the user experiences "I
clicked and the page responded," not an HTMX partial update. See
the HTMX guide: markup
carries structure, the server carries intelligence. |
The field matrix — which design, per field type and context
Reusability decides what ships; suitability decides what a screen uses. When they conflict, the suitable design wins — an unsuitable control damages the UX no matter how reusable it is — and the resolution is always a suitable reusable primitive from this matrix, never a one-off. Contexts follow the editing-design chooser: entry (bordered), read-mostly correction (seamless + row Save/Cancel), and display.
| Field type | Standalone form (entry) | Read-mostly record/table | Editable table (entry grid) | Display |
|---|---|---|---|---|
| Date | Native <input type="date"> in a form field — nothing to add | Seamless type="date" cell | Bordered type="date" cell | Text; status (overdue) as a worded badge — the date contract |
| Number / rate / % | .bo-input--numeric | Seamless numeric | Bordered numeric | Amount |
| Money | Currency selectable → Money ( currency | amount ); fixed → numeric, currency in the label | Seamless numeric; the fixed currency shown as adjacent text | Currency is its own column (fixed per row) → bordered numeric; currency changeable inline (rare) → the joined Money control in the cell | Amount with __currency |
| Quantity | Joined ( qty | unit ) — Quantity; touch/warehouse adds the steppers | Seamless input; unit as text | Unit is its own column → bordered input; unit changeable inline (rare) → the joined control. Steppers never — they belong to touch, not dense grids | Amount with __unit |
Two axes generate every cell: the screen's job picks the chrome (bordered / seamless / plain text), and the qualifier's mutability picks joined-versus-split (changeable next to the value → joined control; fixed → label, adjacent text, or its own column). Nothing in the matrix is a new component — every cell is a setting of the four primitives.
Subtraction is the method
For every element — button, field, colour, screen, feature — the test is: if I remove this, does the user's ability to accomplish the task materially decrease? If no, it goes. Then ask again: 20 things → 12 → 7 → 4 — then ask whether 4 is enough. Simplicity is not minimalism: minimalism is "there aren't many things," simplicity is "I understand what is happening." A dense ERP grid can be simple; a sparse screen can be confusing.
This test is applied to the framework itself, not just to screens built with it. Additions are refused when they serve exactly one scenario or add a second way to do something that already works — and the refusals are recorded with reasons, the same as the things that shipped. If something needs a long explanation to justify its existence, that is the signal it should not exist.
Details are the design
Simplicity takes more effort, not less. Loading, empty, and error states are designed surfaces, not afterthoughts (state patterns); every pattern page documents them in a states table because screens spend most of their life there. Keyboard behaviour, focus order, wording, and print output get the same treatment as the happy path — good design feels inevitable, not impressive.
Scoring alignment — one number per component
Every component carries a Design-System Alignment score: each of the six rules above, plus context-fit against the field matrix, scored 0-3 with a checkable citation (a build gate, a grep, a measured check — never an opinion). Rules that don't apply to a component leave the denominator instead of penalizing it, and the result reads as a percentage: how on-direction this component's design is. The score decides where alignment work goes — it is deliberately a different question from whether a component is worth its surface, which a separate keep/improve/deprecate review answers. Scores live with the review records and are re-taken when a component's design changes.
The shipping filter
Before a screen ships, it faces ten questions — is the purpose statable in one sentence, is the primary action obvious, can anything be removed, does every element have a purpose, does it explain itself, is complexity hidden, is there decoration, are states understandable, does interaction preserve context, and would it look like this built from zero today. A "no" carries a consequence (remove, reword, simplify, redesign) — not a note. Every pattern in this gallery has been through it, and the deeper principle behind all ten:
Design is the process of deciding what deserves to exist. Don't design screens — design decisions. Don't expose processes — expose outcomes. Don't add functionality — remove friction. Don't make complex systems look simple — make them feel simple.