Design system Containers
Widget
A named group with a head: one zone, one job. The head owns the arrangement, never the typography.
.mk-widget
Overview
The widget is a named group with a head — one zone, one job, the rail's own grammar. This page documents the frame, the header variants, and whether the zone opens and closes. The body is deliberately drawn as grey bars — what sits inside belongs to its own components, and a widget that dictated its content would restyle every surface it was migrated onto.
Usage
- Define one named region of a pageUse a widget to group content and controls that serve one clear job within the page composition.
- Keep header roles predictableThe title identifies the region; optional status, hint, disclosure, and contextual actions occupy their defined header slots without replacing the title.
- Let body components keep their contractsThe widget provides structure, surface, and optional collapse behaviour. Lists, tables, forms, and other content inside retain their own spacing and interaction rules.
Anatomy
Variants
Three independent decisions shape a widget: how its header is framed, whether its body can collapse, and whether the header carries a contextual menu. The grid keeps each pair separate so one choice does not imply the others.
States
Collapsible widget
A collapsible widget's header carries the
expander triangle at its left;
aria-expanded lives on that control, the triangle rotates with it,
and closing leaves exactly the header. A static widget carries no triangle. The
collapsible form uses a 64px header because that band must also stand alone as
the complete closed face.
| State | Specimen | What changes |
|---|---|---|
| Open | The header keeps its divider, the content is present, and the expander points toward the available closing movement. | |
| Closed | Only the complete header remains. The title and optional arithmetic stay visible while the expander points toward opening. |
- Closed keeps the arithmeticA collapsed zone's head may carry its count as the hint — the page still answers how much waits inside.
- The triangle is the contractOnly a collapsible head wears it. Decoration that looks like the expander promises an opening that never comes.
When content does not fit
A widget never grows past its share and never hides the overflow behind a
scrollbar. The zone answers with its foot: .mk-widget-more — full
width, the quiet hairline above, the count in the label — extends the zone in
place, and its chevron flips with aria-expanded.
Inner vertical scroll (.mk-widget-scroll) survives
in exactly one seat — the builder's worklist. The pattern is under review; no
new widget takes it without a decision.
Do and don't
One zone, one job: the name states it, and everything inside serves it.
Two jobs under one frame — the widget stops answering "where do I do this", and both zones lose their own seat for an action.
Copy
- The title names the jobA noun phrase for the zone's work — not a section number, not a verb.
- The hint is quiet arithmeticA count or a state the head can carry without shouting.
Accessibility
- The title is a headingReal heading levels, so the rail reads as an outline of zones.
- The collapse is a named control
aria-expandedon the head's expander, its name saying the zone: "Collapse the approvals". The head itself is never the click target dressed as text. - Contained scroll announces itselfWhere the one scrolling seat remains, the cue appears on hover and focus both; keyboard reach is never scroll-only.
When to reach for something else
Markup
<section class="mk-widget">
<div class="mk-widget-head">
<h3 class="mk-widget-title">Widget title</h3>
<button class="mk-btn mk-btn-ghost mk-btn-flush mk-btn-inline" type="button">Quiet action</button>
</div>
<div class="mk-widget-body">…</div>
</section>
<!-- the framed 48px head, agreeing with record-card chrome -->
<section class="mk-widget">
<header class="mk-widget-head mk-widget-head-framed">
<h3 class="mk-widget-title">Widget title</h3>
</header>
<div class="mk-widget-body">…</div>
</section>
<!-- content does not fit: the zone extends by its foot, never by a scrollbar -->
<section class="mk-widget">
<div class="mk-widget-head">…</div>
<div class="mk-widget-body">…</div>
<button class="mk-widget-more" type="button" aria-expanded="false">
Show all 12
<svg data-mk-icon="chevron" aria-hidden="true"></svg>
</button>
</section>
<!-- collapsible: the expander lives in the head, the state on the control -->
<section class="mk-widget">
<header class="mk-widget-head mk-widget-head-framed">
<button class="mk-icon-btn" type="button" aria-expanded="false"
aria-label="Expand the approvals">
<svg class="chev" data-mk-icon="chevron" aria-hidden="true"></svg>
</button>
<h3 class="mk-widget-title">Widget title</h3>
</header>
</section>