Skip to content

dark: utilities key off prefers-color-scheme, so they ignore the dark-mode toggle #559

Description

@mathewtaylor

Found while reviewing #348. The reporter's complaint was about their own dark: classes; the library has the same defect in its own stylesheet.

The defect

Dark mode is switched by adding .dark to <html> — theme-init.js and theme.js both do root.classList.add('dark').

But the library's Tailwind build defines no dark variant, so Tailwind v4 falls back to its default, which is the media query. Every bb:dark: utility in blazorblueprint.css compiles like this:

@media (prefers-color-scheme:dark){
  .bb\:dark\:bg-blue-950{background-color:var(--bb-color-blue-950)}
  ...
}

So those utilities follow the operating system, not the toggle. Turn the app to dark on a machine set to light and they stay light; turn the app to light on a machine set to dark and they stay dark.

Most components are unaffected because they use CSS custom properties (--background, --foreground) that theme.js rewrites when the theme changes. Only the hard-coded dark: utilities are wrong.

Blast radius

9 distinct utilities, 14 usages, 4 components:

  • BbBadge — bb:dark:bg-*-950 / bb:dark:text-*-300 on the semantic variants
  • BbTextarea — bb:dark:bg-input
  • BbBubble
  • BbTreeView (TreeItemNode)

Reproduction

  1. Set the OS to light mode.
  2. Load the demo and toggle the app to dark with BbDarkModeToggle.
  3. Look at a semantic BbBadge, or a BbTextarea background.
  4. They keep their light-mode colour while everything around them is dark.

Fix

Declare the variant in blazorblueprint-input.css so it matches how the class is actually set:

@custom-variant dark (&:where(.dark, .dark *));

That makes bb:dark:* compile against .dark rather than the media query. Worth checking the 14 usages afterwards — some may have been authored against the OS behaviour by accident and will change appearance once this is correct.

The consumer half

The same trap catches anyone running their own Tailwind v4 build alongside the library, which is what #348 actually hit. Their dark:bg-none applies in light mode too, because their build has no custom variant either and the library sets a class rather than relying on the OS.

Nothing documents this. It belongs in THEMING.md and the migration guide next to the border-colour rule from #527, because it is the same shape of problem: a thing a consumer must add to their own stylesheet to make their build agree with the library's.

@layer base {
  @custom-variant dark (&:where(.dark, .dark *));
}

Not a bug: the persistence half of #348

The other half of that discussion — dark mode resetting on reload or navigation — is theme-init.js missing from <head>. It is documented in README and THEMING.md and every demo host uses it. Answering that in the discussion rather than here.

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions