fix: add Suspense boundaries to prevent React #426 during i18n loading - #2654
Merged
serikjensen merged 12 commits intoAug 27, 2026
Conversation
Several components called useI18n() above their nearest Suspense boundary. When a user navigated to these components via a synchronous state-machine transition and the i18n namespace was not yet cached, useI18n suspended above the boundary and React threw error #426. The fix follows the same pattern as #2554: move useI18n into an inner component rendered inside BaseBoundaries so the suspension is caught by the component's own Suspense boundary. Affected components: - Employee Dashboard contextual wrapper (DashboardViewContextual) - Contractor Dashboard contextual wrapper (DashboardViewContextual) - TerminateEmployee/TerminationSummary contextual wrappers - InitialEditCompensation/EditCompensation contextual wrappers - PayrollLandingTabs contextual wrapper (also has suspense queries) - InformationRequestsFlow (standalone, no boundary at all) - OffCycleDeductionsSetting (leaf component, no boundary)
…TerminationSummary Instead of wrapping contextual wrappers in BaseBoundaries, remove the suspending useI18n calls entirely — the underlying components (Dashboard, EditCompensation, TerminateEmployee) already load their namespaces inside their own boundaries. For TerminationSummary, the cancelSuccess translation is moved into the component itself so the contextual wrapper no longer needs useI18n or event interception. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDj8FTh4FwRJfJJGdsZF1j
useTranslation also suspends by default (useSuspense: true in react-i18next v17), so the previous fix of only removing useI18n was insufficient. This moves all translation-dependent logic into the underlying components where it runs inside BaseBoundaries: - Dashboard (Employee/Contractor): add successAlert prop, render alert inside DashboardRoot (inside BaseBoundaries) - EditCompensation: make title/submitCtaLabel optional, add mode prop to select defaults computed inside Root (inside BaseBoundaries) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDj8FTh4FwRJfJJGdsZF1j
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDj8FTh4FwRJfJJGdsZF1j
#426 Wraps the active step component in Flow.tsx with <Suspense> so that useI18n/useTranslation calls in contextual wrappers don't throw React #426 during synchronous state-machine transitions. Reverts earlier approach that moved translations/alerts into public component APIs (Dashboard, EditCompensation) — the Flow-level boundary is the systematic fix that protects all contextual wrappers without changing public interfaces. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDj8FTh4FwRJfJJGdsZF1j
…llback Revert changes to TerminationFlowComponents, TerminationSummary, and PayrollLandingFlowComponents that are now redundant with the Flow-level Suspense boundary. Use the SDK loading indicator as the step fallback instead of null. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDj8FTh4FwRJfJJGdsZF1j
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDj8FTh4FwRJfJJGdsZF1j
dmortal
approved these changes
Aug 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes React #426 errors caused by
useI18n()anduseTranslation()suspending without a Suspense boundary during synchronous state-machine transitions. The core fix adds a Suspense boundary around step components inFlow, which systematically protects all contextual wrappers rendered as Flow steps. Two standalone components that aren't rendered by Flow also get their ownBaseBoundarieswrappers.Changes
Flow.tsx: Wrap the active step component in<Suspense fallback={<LoadingIndicator />}>, matching the existing pattern used forFlowHeaderInformationRequests.tsx: AddBaseBoundarieswrapper (standalone component not rendered by Flow, had no outer Suspense boundary)OffCycleDeductionsSetting.tsx: AddBaseBoundarieswrapper (standalone public component, had no outer Suspense boundary)Testing
npx tsc --noEmitpassesnpm run test -- --run— 347 passed, 2 flaky timeouts in unrelatedPaymentFlow.test.tsxnpm run test -- --run src/components/Flow/Flow.test.tsxScreen.Recording.2026-08-27.at.9.25.07.AM.mov
Screen.Recording.2026-08-27.at.9.27.16.AM.mov
Screen.Recording.2026-08-27.at.9.30.06.AM.mov
Generated by Claude Code