Workshop Kit · widget reference

Shipped

drag-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"

Current MuntinContext (the two demo keys above, ranked id-arrays) Reorder something above…

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.

AttributeTypePurpose
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

<section class="course-widget" data-widget="drag-rank" data-context-key="siteJobsRank" data-severity="true" data-instruction="What's a site for? Rank from most to least important." data-instruction-es="¿Para qué sirve un sitio? Ordena de más a menos importante."> <script class="drag-rank-items" type="application/json"> /* id is stable; label / desc are visible; -es variants per locale */ [ {"id":"book","label":"Book a table","label-es":"Reservar una mesa", "desc":"Diners arriving via OpenTable.","desc-es":"Comensales llegando vía OpenTable."}, /* … */ ] </script> </section>

Keyboard model

No HTML5 drag-and-drop. Every reorder goes through the up/down buttons on each row, which means:

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

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.

← Back to the Workshop Kit