Skip to content

fix: [DHIS2-21286] fix scrolling to first validation error in tracker/event forms#4592

Draft
karolinelien wants to merge 1 commit into
masterfrom
fix/DHIS2-21286-validation-error-scroll-positioning-v2
Draft

fix: [DHIS2-21286] fix scrolling to first validation error in tracker/event forms#4592
karolinelien wants to merge 1 commit into
masterfrom
fix/DHIS2-21286-validation-error-scroll-positioning-v2

Conversation

@karolinelien
Copy link
Copy Markdown
Contributor

@karolinelien karolinelien commented May 28, 2026

Summary

Fixes two bugs that caused the scroll-to-first-error on save to land in the wrong place. Affects every entry point that uses withSaveHandler (TE registration, enrollment registration, single-event registration, new event in enrollment, edit event) — i.e. both tracker and event programs.

  • B1 — D2Form section data elements never scrolled. withGotoInterface was wrapped in forwardRef during the React 18 migration (09ed283). That redirected the parent's ref from GotoFieldInterface to the inner field component, which doesn't expose a goto() method, so instance.goto && instance.goto() in D2Form.validateFormScrollToFirstFailedField silently no-op'd for every section field. Drop the forwardRef wrapper — no consumer reads the forwarded ref. This explains the pre-fix asymmetry where save would scroll to OccurredAt (which uses DataEntryField's own goto()) but not to a section mandatory DE.
  • B2 — top-of-form fields (e.g. OccurredAt) landed behind the sticky ScopeSelector bar. Both goto() implementations did scrollIntoView() and then post-corrected with window.scroll(0, scrolledY - 48). The if (scrolledY) guard skipped the correction when scrolledY === 0 (which is exactly what happens when the field is near the top of the document), leaving the field flush with the viewport top — under the sticky ScopeSelector. Replace with scrollIntoView({ block: 'start' }) + scrollMarginTop: '80px' on the wrapper so the browser lands the field 80px below the viewport top regardless of position. 48px covers the SelectorBar height, the remaining 32px is breathing room above the label.

Same fix pattern applied to both call sites (withGotoInterface for in-section data elements and DataEntryField for top-of-form fields).

Test plan

Save is always at the bottom of the form, so the only scroll direction validation needs to drive is up.

  • Tracker program stage, OccurredAt empty, click Save → page scrolls UP, OccurredAt label clear of ScopeSelector (tests B2 via DataEntryField)
  • Tracker program stage, mandatory section data element empty, click Save → page scrolls UP, that field's label clear of ScopeSelector (tests B1 — broken on master)
  • Event program (single-event registration), OccurredAt empty, Save → scrolls UP, label clear of ScopeSelector
  • Event program (single-event registration), mandatory section DE empty, Save → scrolls UP, label clear of ScopeSelector (tests B1 on the event-program path)

AI Assisted

…ector

Two bugs caused validation-failure scroll to land in the wrong place:

1. withGotoInterface wrapped its class in forwardRef during the React 18
   migration (09ed283). The outer ref then pointed at the inner field
   component, not GotoFieldInterface, so .goto() silently no-op'd on every
   D2Form section field. Drop the wrapper - no consumer reads the
   forwarded ref.

2. Both goto() implementations did scrollIntoView() then post-corrected
   with window.scroll(0, scrolledY - 48). The guard skipped the correction
   whenever scrolledY === 0 (e.g. OccurredAt near top of doc), leaving the
   field flush with the viewport top - and behind the sticky ScopeSelector
   bar. Use scrollIntoView({block:'start'}) + scrollMarginTop:80px on the
   wrapper so the browser lands the field 80px below the viewport top
   regardless of position.

AI Assisted

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown

@karolinelien karolinelien changed the title fix: [DHIS2-21286] scroll first failed field clear of sticky ScopeSel… fix: [DHIS2-21286] fix scrolling to first validation error in tracker/event forms May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant