Workshop Kit · widget reference
Shippedweekly-hours-grid
Seven rows — one per day — with native <input type="time"> open and close pickers plus a "closed" checkbox. A "copy Monday to Friday" shortcut at the top fills the work-week from Monday's row in one click. Writes a single hours object to MuntinContext that the L14 generator's contact page reads as the seven-day table.
Live demo
Set Monday's open + close, click "copy Mon→Fri" to fill the rest of the work-week, mark Sunday closed. Open the live-state below to see the exact hours object the contact-page template reads.
data-context-key="hours" (always — the L10 lesson uses no other config)
Contract
No data attributes beyond data-widget. The widget always writes to hours and renders the seven-day grid in week order (Monday first, Sunday last — the operator-friendly week starts on the work-day, not the calendar-week's Sunday).
| Attribute / behavior | Notes |
|---|---|
data-widgetRequired |
Always "weekly-hours-grid". |
Writes MuntinContext.hours |
An object keyed by day name (monday, tuesday, …, sunday), each value { open: string, close: string, closed: boolean }. Times are 24-hour strings ("11:00", "21:00") — what <input type="time"> natively emits. |
| "Copy Mon→Fri" shortcut | Disabled when Monday is closed (would propagate emptiness across the work-week — destructive default). When Monday has open/close set, one click fills Tuesday–Friday with the same pair. Polite-region announcement names what got copied where. |
| Closed checkbox | When checked, the day's open/close inputs disable + the row dims. The closed=true value persists so the generator emits a "Closed" cell on contact.html. Unchecking restores the previously-typed times (preserved in state, never erased by the checkbox toggle). |
Markup
That's the whole call site. The L10 lesson mounts exactly this; nothing else configures.
Why native time inputs, not a custom picker
<input type="time"> on mobile gets the OS's native time picker — the same one the operator uses for their phone alarm, with the same accessibility, the same 12/24-hour formatting, the same screen-reader behavior. A custom picker would be more visually consistent across browsers; native is what the operator's muscle memory already knows.
The trade-off: time inputs render slightly differently in each browser. That's the smaller of two evils. The L14 generator normalizes the output to "HH:MM – HH:MM" strings, so the rendered contact page is identical regardless of which browser the operator edited from.
Why Monday first (not Sunday)
The widget renders days in monday, tuesday, …, sunday order. Standard calendar UI puts Sunday first — that's a leftover from print calendars optimized for "which week is this." Restaurant operators care about which day they're open; for the work-week-first cuisines (most American breakfast/lunch, most office-district operators), Monday is the natural start. Sunday-first calendars push the work-week to the visual center, splitting it across two rows in the operator's head.
Where it ships
L14's generator reads the same hours object and renders contact.html's hours table. The L13 lesson references hours as a first-week trust signal; the L16 rhythm includes a monthly hours-check as one of the four recurring tasks.
Source
/tools/_shared/workshop/weekly-hours-grid.js — ~280 LOC. Exports { tag, contextKeys, mount, serialize } per the Workshop Kit widget contract. Renders the seven rows in fixed order, wires per-day open/close/closed change handlers, manages the Mon→Fri shortcut's disabled-when-Monday-closed guard, and announces every action via the polite live region.
State preservation on closed: when the operator checks "closed," the existing open/close strings stay in state (just visually dimmed). Unchecking restores them — no silent data loss from a toggle. A common operator mistake is checking closed to "save a draft for later"; the preserved state means they don't lose what they typed.