Skip to content

fix(ui): prevent light-theme flash during dark and system-mode startup #54

Description

@Proxicon

Summary

On deployed v0.1.0-rc.8, a first arrival or browser refresh can briefly render a light/white application palette before the selected dark palette appears. This affects System mode on a dark OS/browser and explicit Dark; explicit Light on a dark OS is the reverse-polarity control. Public portal link navigation can expose the transition, and authenticated full refreshes are affected.

Reproduction

  1. In a fresh browser context, prefer dark at the OS/browser level.
  2. Use System, then load or refresh /; repeat with an explicit Dark selection.
  3. Observe the first rendered page and public portal links such as /submit-ticket and /view-ticket.
  4. As a control, select explicit Light while the OS prefers dark.

Expected behavior

The first app-controlled visible frame must use the resolved preference for canvas, body, text, app bar, drawer, cards/paper, inputs, and overlays. It must remain stable through prerendering, interactivity startup, layout replacement, full reload, enhanced navigation, and runtime System-mode changes. Explicit Light must override a dark OS just as explicit Dark overrides a light OS.

Verified source findings

  • App.razor has an early inline bootstrap that assigns data-helpdesk-theme, but it does not initialize MudBlazor palette variables and its storage reads are unguarded.
  • ThemePreferenceProvider initially renders System/light and only loads the saved preference after render.
  • The actual surface colors depend on Mud palette variables, so an early document attribute alone cannot prevent a light first palette.
  • Bootstrap exact string comparisons and provider trim/lowercase parsing differ.

The current working hypothesis is that the bootstrap document attribute and the provider's initial Mud palette disagree until interactive initialization completes; this will be verified against the served HTML and browser-computed styles.

Affected scope

Public root and public links, login/shared shell, authenticated hard reloads, and layout replacement. Preserve the existing lightweight public-root loading behavior, branding, authenticated navigation, CSP posture, preference key (helpdesk.theme.preference), and three-mode selector. This excludes UI redesign, new persistence/state systems, dependency/version changes, release, and deployment.

Acceptance criteria

  • Normalize stored dark, light, system, missing, invalid, mixed-case, and whitespace values consistently; failures reading/writing storage fall back safely.
  • Resolve and apply the effective palette synchronously before visible app content, while retaining CSS fallback when JavaScript is unavailable.
  • Synchronize the provider to the existing resolved state without an initialization or layout-transition flash; System observes OS changes and explicit selections ignore them.
  • Add a deterministic pre-interactivity regression that pauses noncritical runtime startup and asserts real computed page/surface/text colors before and after release, plus normal lifecycle/navigation coverage.
  • Measure and document the preserved public-root startup/request behavior.

Implementation branch: fix/theme-first-paint from origin/main at 1aac8ab32e1b8720a801dfb26e0754a3edd1c007.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    UXUX-Blazor RelatedbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions