Repository navigation
GUI consistency: no density token scope and no part contracts, so views hand-roll spacing and reach into primitive internals #17564
Description
Part of #12730. Two mechanisms the shared primitives do not expose, both of which push views into hand-rolling the thing the umbrella wants standardised.
Problem 1 — there is no density scope
autobot-frontend has a large token layer (src/assets/css/design-tokens.css, 698 custom properties) but spacing density is not part of it. --card-padding is declared once; there is no --table-row-height, no --table-cell-py, and no density scope class. So every table and card carries literal spacing, and a user-facing compact/comfortable/spacious control is not expressible without touching every component.
The mechanism that avoids per-component size props entirely is a scope class on an ancestor that redefines a handful of spacing tokens — four is enough (--table-row-height, --table-cell-py, --card-padding, --spacing-unit). Components consume var(--…) and never learn density exists.
Problem 2 — composite primitives have no addressable parts
Cards, tables and panels expose no named internal parts. A view that must restyle a card header or a table cell therefore reaches in with its own class — and each reach is a fresh divergence that no linter sees, because the class is locally valid.
A part-contract convention (a stable data-slot="card-header"-style attribute on each internal region, targeted by the stylesheet) makes the internals a declared API instead of an accident of DOM shape.
Both are cheap once the primitives are single-sourced, and both are wasted effort before that — hence the dependency below.
Approach
- Add the four density tokens to
design-tokens.csswith the current values as the comfortable default, so nothing moves on landing. - Add
.density-compact/.density-comfortable/.density-spaciousscope classes that redefine only those tokens. - Make the kit's card and table primitives consume the tokens instead of literal spacing.
- Define the part-name convention in the kit's docs, apply it to the primitives merged by Retire the local Base* component forks in autobot-frontend into the shared kit #14776/Promote BaseInput, BasePanel and BaseTable into the shared kit #14778, and state that a part name is a public API — renaming one is a breaking change.
- Do not retrofit part names ad hoc onto unmerged forks; that is how a third namespace starts.
Acceptance criteria
-
--table-row-height,--table-cell-py,--card-padding,--spacing-unitdeclared indesign-tokens.css, with the comfortable values equal to today's rendering (no visual diff). - Three density scope classes exist and redefine only those tokens.
- The kit's card and table primitives reference the tokens, with no literal padding or row height remaining.
- Switching the scope class on an ancestor visibly changes table row height and card padding, with zero component prop changes (test or story).
- The part-name convention is documented in the kit, and every primitive merged by Retire the local Base* component forks in autobot-frontend into the shared kit #14776/Promote BaseInput, BasePanel and BaseTable into the shared kit #14778 carries part names on its internal regions.
Implementation Order
Wave: 3
Depends on: #14776, #14778, #14785
Unblocks: —
Evidence
src/assets/css/design-tokens.css — 698 --var: declarations, --card-padding declared once, no row-height or cell-padding token · no part-name attribute convention anywhere in libs/autobot-ui or autobot-frontend/src/components.
Found during a comparative GUI-standardisation audit — see docs/research/dashboard-shell-and-component-standardisation.md, gaps G3 and G4.
Activity
mrveiss commentedon Sep 26, 2026
Second GUI: the density half does not apply yet, the part-contract half applies more
Audited after filing.
Density.
autobot-slm-frontenddefines 173 tokens of its own (src/assets/styles/main.css152 +src/assets/styles/aui-theme.css43) and referencesvar(--…)in only 12 of 113 component files. A density scope class works by redefining tokens that components consume — so in the SLM GUI it would currently change almost nothing. Density must therefore land after #17566 (the SLM tokenisation sweep), or it ships working in one GUI and inert in the other.Part contracts. These apply more strongly there, not less: with no table primitive, no page header and no breadcrumb, every SLM view builds its own internals, so there is nothing whose parts could be addressed. Defining the convention while the kit primitives are being merged (#14776/#14778) and built (#17563) is the cheap moment; retrofitting 113 files later is not.
One counter-measurement, so the "local override" framing is applied to the right GUI. Components that redefine a design token inside their own
<style>:autobot-frontendcomponents/workflow/WorkflowCanvas.vuealone: 18)autobot-slm-frontend!importantin component<style>: 14 files / 58 uses (main) vs 3 files / 4 uses (SLM).So the token-level local overrides are entirely a main-GUI problem, while the palette-class local overrides are overwhelmingly an SLM problem (6,213 vs 689 — #17566, #14580). Two different failure modes under one owner rule; a single check will not find both.
docs(research): dashboard shell and GUI-element standardisation audit (…
docs(research): dashboard shell and GUI-element standardisation audit (…
fix(theme): one themed source for notification colour, and a ratchet …
fix(theme): ember stops being the default palette, and density scales…