Symptom
In dash's /test-calendar route, section 7 — Full suite inside a form (bridge + validation), clicking on a valid weekday inside the Start date DatePicker's calendar popup does NOT commit the selected value to the form field. The popup closes but the input stays empty.
Discovered while
Manual visual smoke test during Sprint 5 pre-flight for issue #60 (Option C). Reported by @kensaadi 2026-07-12 during the dash smoke session.
Repro
cd ~/projects/web/learn/dash && pnpm dev (or open http://localhost:5176 with dash already running)
- Navigate to
/test-calendar
- Scroll to section 7 — Full suite inside a form (bridge + validation)
- Click the calendar icon on the Start date (required, weekdays only) input → calendar popup opens
- Click a valid weekday within the min-max range (e.g. May 15, 2026 — a Friday, not weekend, within
minDate='2026-05-01' / maxDate='2026-07-31')
- Observe: the calendar popup closes, BUT
- The Start date input remains empty — the selected value never gets committed to the form field
Diagnostic evidence (from live session)
Ran during repro:
```js
const day = Array.from(grid.querySelectorAll('button')).find(b => b.textContent?.trim() === '15');
day.click();
// After: input.value === '' (still empty)
// After: popup closes (data-dialog gone)
// After: 0 console errors
```
The day button IS a real button with:
disabled: false
aria-disabled: 'false'
aria-label: 'Friday, May 15, 2026'
But the click:
- Does NOT call
handleCalendarChange → does NOT reach commitValue → does NOT trigger bridge.setValue
- Does close the popup (
ClickAwayListener or a Radix outside-click may be swallowing focus)
What is NOT the cause
- Not React duplicate: dash uses a single React 19.2.7 instance
- Not a min/max issue: May 15 2026 is well within the configured range
- Not
isDateDisabled: verified disabled=false on the button
- Not a bridge issue: same pattern works in section 3 (DatePicker standalone) — the standalone version DOES commit the value (verified by checking `Value: ...` display)
Suspected root cause
Calendar (in @dashforge/ui) day-button `onClick={() => calendar.selectDate(day.iso)}` — the `selectDate` call chain in `useCalendar` (from `@dashforge/calendar-core`) is not firing the parent's `onChange` prop when the value TRANSITIONS from `null` to a valid date inside a form-bridge context. Behavior might be specific to the form-integrated path (`resolvedValue = bridgeValue ?? null`) — the standalone path (section 3) has different value plumbing and works.
Acceptance
Versions
Related
Symptom
In dash's
/test-calendarroute, section 7 — Full suite inside a form (bridge + validation), clicking on a valid weekday inside the Start date DatePicker's calendar popup does NOT commit the selected value to the form field. The popup closes but the input stays empty.Discovered while
Manual visual smoke test during Sprint 5 pre-flight for issue #60 (Option C). Reported by @kensaadi 2026-07-12 during the dash smoke session.
Repro
cd ~/projects/web/learn/dash && pnpm dev(or open http://localhost:5176 with dash already running)/test-calendarminDate='2026-05-01'/maxDate='2026-07-31')Diagnostic evidence (from live session)
Ran during repro:
```js
const day = Array.from(grid.querySelectorAll('button')).find(b => b.textContent?.trim() === '15');
day.click();
// After: input.value === '' (still empty)
// After: popup closes (data-dialog gone)
// After: 0 console errors
```
The day button IS a real button with:
disabled: falsearia-disabled: 'false'aria-label: 'Friday, May 15, 2026'But the click:
handleCalendarChange→ does NOT reachcommitValue→ does NOT triggerbridge.setValueClickAwayListeneror a Radix outside-click may be swallowing focus)What is NOT the cause
isDateDisabled: verifieddisabled=falseon the buttonSuspected root cause
Calendar(in@dashforge/ui) day-button `onClick={() => calendar.selectDate(day.iso)}` — the `selectDate` call chain in `useCalendar` (from `@dashforge/calendar-core`) is not firing the parent's `onChange` prop when the value TRANSITIONS from `null` to a valid date inside a form-bridge context. Behavior might be specific to the form-integrated path (`resolvedValue = bridgeValue ?? null`) — the standalone path (section 3) has different value plumbing and works.Acceptance
Versions
engine.getNode()API in@dashforge/forms#2)Related