fix(cli): sync scaffold dark mode so ui-* components follow the theme#101
Merged
Conversation
The default scaffold shipped two unsynced theme systems: the editorial chrome tokens (--fg/--bg) toggled via a `data-theme` attribute, while the copied shadcn ui-* components (button, card, alert, etc.) key their dark tokens off a `.dark` class (`@custom-variant dark (&:is(.dark *))`). Nothing ever set `.dark`, so every ui component was frozen in light tokens. On the dark-default chrome this rendered, e.g., the outline "View docs" button as white-on-light (invisible text) and cards as white boxes. Light mode looked fine only because both systems were light then. Fix: the head init script and the theme-toggle now toggle a `.dark` class in sync with the effective theme (dark by default unless the OS prefers light or 'light' is chosen), and the head script re-applies on OS theme changes. The chrome's `data-theme` mechanism is unchanged; the `.dark` class simply drives the shadcn tokens alongside it. Verified in a browser (emulated dark): outline button now renders with the dark input tint + light text, cards render dark, and light mode is unchanged.
Codify why dark mode broke while light worked so it can't recur silently: - agent-docs/styling.md: new "Dark mode" section explaining the two theming signals (data-theme for the editorial chrome, .dark class for the Webjs UI kit), that a theme switch must drive both, and that light mode passing proves nothing about dark mode. - agent-docs/testing.md: a "Verifying UI and theming" note: render in a real browser, test both themes, inspect computed styles, read the screenshot, and guard the wiring in a fast test. - test/scaffolds/scaffold-integration.test.js: assert the generated layout head script AND theme-toggle both toggle the `.dark` class, so the sync mechanism can't regress unnoticed. - templates/CONVENTIONS.md: a scaffolded-app note mirroring the dual-signal rule for agents working inside a user app.
2 tasks
vivek7405
added a commit
that referenced
this pull request
May 25, 2026
Ship the scaffold dark-mode fix (#101): newly scaffolded apps now sync the shadcn `.dark` class with the theme, so ui-* components render correctly in dark mode. create-webjs and webjsdev lockstep to 0.9.1 via the release workflow.
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.
Bug
In a default-scaffolded app, the dark theme is broken for every copied
components/ui/*component. The reported symptom: the "View docs" (outline) button renders white-on-light (invisible text) in dark mode; light mode is fine.Root cause
The scaffold ships two unsynced theme systems:
--fg/--bg, dark-by-default) toggled via adata-themeattribute on<html>.--background/--foreground/etc.) whose dark tokens key off a.darkclass (@custom-variant dark (&:is(.dark *))).Neither the head init script nor the theme-toggle ever set a
.darkclass, so the shadcn tokens were permanently stuck in light mode. On the dark chrome that meansbg-background= white, etc. Reproduced in a browser (emulated dark):oklch(1 0 0)white, light text → invisibleinput/30tint + light text → readable0.205dark, light textLight mode only "worked" because both systems happened to be light.
Fix
The head init script and
theme-toggle.cycle()now toggle a.darkclass in sync with the effective theme (dark by default unless the OS prefers light orlightis chosen), and the head script re-applies on OS theme changes. Thedata-themechrome mechanism is unchanged;.darkjust drives the shadcn tokens alongside it.Verification
Browser-tested against a live scaffolded app (
/usr/bin/chromium, emulated dark + light):.darknow present; outline button + card + alert + badge render dark-correct (screenshot reviewed).npm testgreen via pre-commit hook (1151/1151).Follow-up note (not in this PR)
Minor secondary gap: the scaffold chrome's
--accent(brand orange) and shadcn's--accentcollide by name, so ui-* hover states (hover:bg-accent) use the orange instead of shadcn's accent. Hover-only and arguably acceptable as a brand accent; flagging for a separate decision.