Skip to content

Time boxes are fiddly on desktop: every time input uses the browser's segmented box #686

Closed

Description

@richshaw

What happens

Every place OpenSignup takes a time of day uses the browser's own <input type="time">:

  • The builder's slot editor: each Time cell (SlotEditor.tsx, which spreads FIELD_VALUE_INPUTS.time from src/components/build-shared/fieldTypes.ts).
  • Magic Compose's questions screen, from Show Magic Compose's questions, and say what a draft needs #576: "One day" shows a start and an end time in one box (When in src/components/magic-compose/Questions.tsx). Only a dash separates them, and their labels are for screen readers only.

On a phone this opens the system's time wheel, which is fine. On desktop it's a segmented --:-- -- box: you click into the hour, type it, move to the minutes, then to AM/PM. Typing "9am" doesn't work. The owner found it hard to use on desktop while tophatting #577. On the questions screen you can also pick an end before the start, and the error only shows after pressing Draft my signup.

Fix, in outline

  • One standard time control. Add a TimeSelect component in src/components/build-shared/: a native <select> of times in 15-minute steps. Label each option in the 12-hour style the public page uses (formatSlotTime in src/lib/slot-label.ts). Values stay "HH:MM" 24-hour, so nothing changes on the server, in emails or in reminders.
  • Make it the only way the app takes a time. Remove the time entry from FIELD_VALUE_INPUTS, so no new code can fall back to the native box. Use TimeSelect everywhere a time is entered.
  • The empty choice. When a time is optional, the first option is empty ("No time").
  • Times off the 15-minute grid. A value like 09:10 can come from the AI, the AI connector or an older edit. Show it as its own option, so opening an editor never changes it.
  • Start and end pairs. TimeSelect takes an optional after time. When given, it lists only later times, each with its length ("9:15 AM (15 min)", "1:00 PM (4 hr)").
  • Typing still works. On desktop a native select jumps to the first option that starts with what's typed ("9" goes to 9:00 AM). Phones keep their own picker.
  • The questions screen shows two visibly labelled controls, "Starts" and "Ends". Ends passes after = the start. If the start moves to or past the chosen end, the end clears. Keep the end-after-start check in answersProblem (answers.ts) as a safety net; the server checks it too.
  • The builder's Time cell renders TimeSelect for one time.

Watch for

  • The builder's page budget. /app/signups/[id]/build is at 159.6 of its 160 kB first-load budget (CI on Ask a few questions when a Magic Compose description doesn't say what people sign up for #577). Build the option list with a small function rather than a table, and run pnpm build && pnpm budgets. Raising a budget is the owner's call.
  • Tests that pin the native input. SlotEditor.test.tsx checks that the "Time value" box is type="time". Questions.test.tsx sets "Start time (optional)" and "End time (optional)" with fireEvent.change. Any e2e or help walkthrough that fills a time needs selectOption.
  • Labels. The builder cell keeps its accessible name "Time value". The questions screen's labels become visible, so its tests and the help article's names may change.
  • Help pages. Run the help-pages skill's affected-articles check for any article or screenshot that shows a Time cell or the questions screen.
  • Overnight times stay unsupported on the questions screen (the end must be after the start), as Show Magic Compose's questions, and say what a draft needs #576 decided.
  • CHANGELOG gets a line.

Order

After #577, because the questions screen arrives with the #572 → #577 stack (#576 adds it), which isn't on main yet.

Done when

  • FIELD_VALUE_INPUTS has no time entry, and no type="time" input is left in src.
  • A unit test pins the option list: 15-minute steps, 12-hour labels, an off-grid value kept, and with after, only later times with their lengths.
  • Component tests:
    • Questions screen: Ends lists only later times, and clears when the start passes it.
    • Builder: a Time cell saves a picked time, and an off-grid value survives opening and closing the editor.
  • pnpm lint && pnpm typecheck && pnpm knip && pnpm test, pnpm test:db, pnpm build && pnpm budgets and the e2e suite pass.

From the owner, while tophatting #577 at b8f2e66: the time boxes are hard to use even on desktop. The owner chose two dropdowns over a parsed text box or a tidied native input, and asked for one standard component for every time input. Checked against b8f2e66 and main at 025fe6f: the builder's Time cell and the questions screen are the only time inputs in src.


Generated by Claude Code

Activity

  1. self-assigned this
    on Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions