Workshop Kit · widget reference
Shippeddrag-rank
A keyboard-first force-ranker. Operators reorder a list of cards by clicking up/down buttons; the widget commits the new id-order to a context key on every change. Optional severity coloring highlights the top third (red, urgent) and dims the bottom third — useful for the "what's leaking" diagnostic and the "what matters most" forced-prioritization patterns.
Live demo
Two variants — a neutral ranker (no severity coloring) and a severity ranker that visually flags the top third as urgent. Both write to MuntinContext; reorder, reload, your order persists.
Neutral · data-context-key="demoSiteJobs"
Severity coloring · data-severity="true"
Contract
The widget reads its items from an inline JSON config block. The lesson author names the context key + (optional) instruction + (optional) severity flag via data attributes. The widget engine handles discovery, hydration, and commit.
| Attribute | Type | Purpose |
|---|---|---|
data-widgetRequired |
literal | Always "drag-rank". |
data-context-keyRequired |
string | Where the ranked id-array lands in MuntinContext. The shape is ["id1", "id2", …] — an array of the item ids in current order. |
data-instruction |
string | Prompt rendered above the list. data-instruction-es for the Spanish copy on the same widget instance. |
data-severity |
boolean | Set to "true" to visually mark the top third as urgent (red border) and dim the bottom third. Useful for diagnostics; off by default. |
<script class="drag-rank-items" type="application/json">Required |
JSON array | Inline items config — array of {id, label, label-es, desc, desc-es} objects. id is the stable identifier written to context; label/desc render visually. The widget renders items in the current order (from context if present, else the source order). |
What it writes: on every reorder, the widget commits the id-array to the named context key, broadcasts mtn:context-change, and announces the move via a polite live region (e.g., "Phone goes to voicemail moved to rank 1 of 6"). Hydration on mount restores the saved order; new items added to the items config but absent from the saved order land at the end.
Markup
Keyboard model
No HTML5 drag-and-drop. Every reorder goes through the up/down buttons on each row, which means:
- Tab walks the list. Each item is focusable; arrow keys move within the buttons.
- The up/down buttons are real
<button>elements. Pressing one moves the item one rank. Focus stays on the same button after reorder (so you can keep pressing to move multiple positions). - Polite live region announces the new rank to screen readers ("Phone moved to rank 1 of 6") so AT users hear the structural change.
- First / last items have their up / down buttons disabled appropriately — no orphan keyboard target at the edges.
This is deliberate. HTML5 drag-and-drop is unreliable on mobile, hostile to keyboard navigation, and historically inaccessible. Buttons + live region beats it on every axis that matters for the operator.
Where it ships
- L2 — What a site that books tables actually does (5 jobs ranked)m1-orient/what-a-site-does
- L5b — Audit your current site (drag-rank what's leaking)m2-decide/rebuild/audit
- L6b — Diagnose what's leaking (severity coloring on)m2-decide/rebuild/leaks
- L9a — Photo brief from scratch (8 shot types ranked)m3-assemble/fresh/photos
- L9b — Photo refresh triagem3-assemble/rebuild/photos
- L11b — GBP repair (priorities to fix this week)m3-assemble/rebuild/gbp
Source
/tools/_shared/workshop/drag-rank.js — ~250 LOC. Exports { tag, contextKeys, mount, serialize } per the Workshop Kit widget contract. Reads inline JSON items, renders the list, wires the up/down buttons, manages focus + polite live region, commits the id-array on every reorder.
Hydration order: saved state (from MuntinContext[contextKey]) wins, then unknown ids from the items config get appended at the end. Renamed item ids (a config change) leave the old id orphaned in the saved state — the widget logs a warning to the console and renders the remaining items in their canonical order.