fix(styles): isolate module's Tailwind utilities in a lower cascade layer#17
Merged
Conversation
…ayer
Modules generated from this template were silently breaking the
Backoffice Shell sidebar: when the module was active, clicking the
sidebar trigger flipped the `data-state` to `expanded` but the sidebar
element stayed at `display: none`. Reproduced live in
`front-scholarship-funds` (fix shipped there as well).
Root cause: cascade order on `.hidden`. The shell uses `hidden md:block`
(shadcn sidebar) and emits both `.hidden` and `.md\:block` in its
stylesheet. The module does not use `md:block`, so Tailwind 4 emits
only `.hidden` for the module. `vite-plugin-css-injected-by-js`
appends the module's <style> after the shell's stylesheet, and inside
the shared `@layer utilities` the later-source rule wins — so the
module's `.hidden` defeats the shell's `.md\:block`, even on a wide
viewport.
Fix: declare the module's auto-generated utilities in a dedicated
`module-utilities` layer that sits below the global `utilities` layer
the shell occupies. The shell's `.md\:block` now wins by layer
priority regardless of <style> injection order. Manual utilities a
module adds later via `@layer utilities { ... }` keep the
high-priority layer, so module-specific visuals still apply where
intended. `@theme` gets the same treatment (`module-theme`) for
symmetry — module theme tokens point at shell tokens via `var(...)`,
so shell `theme` rules winning on conflicts is the desired behavior.
This is the same family of bug as the existing Preflight gotcha
already documented at the top of globals.css; the comment is expanded
to cover both.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Este PR ajusta a forma como o template do módulo importa o Tailwind para evitar colisões de utilitários com o Backoffice Shell quando o CSS do módulo é injetado depois do CSS do shell, garantindo que utilitários responsivos do shell (ex.: md:block) prevaleçam sobre utilitários “base” do módulo (ex.: hidden).
Changes:
- Introduz camadas de cascata dedicadas (
module-themeemodule-utilities) com menor prioridade. - Redireciona os imports
tailwindcss/theme.cssetailwindcss/utilities.csspara essas novas camadas. - Expande a documentação em
globals.csspara registrar o gotcha de ordem de cascata (além do já existente sobre Preflight).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+9
to
+22
| * css-injected-by-js, that reset would apply to every element on | ||
| * the page — including the shell's chrome. Symptom: sidebar/header | ||
| * borders disappear, layout shifts. Fix: import only `theme` and | ||
| * `utilities`, never the full `tailwindcss` entry. The shell ships | ||
| * its own Preflight once for the whole page. | ||
| * | ||
| * 2) Cascade order on shared utilities (`.hidden`, `.flex`, `.block`). | ||
| * Tailwind 4 emits only the utilities each project actually uses. | ||
| * The shell uses `hidden md:block` (shadcn sidebar) but a module | ||
| * typically does not — so the shell's stylesheet contains BOTH | ||
| * `.hidden` and `.md\:block`, while the module's stylesheet | ||
| * contains ONLY `.hidden`. css-injected-by-js appends the module's | ||
| * <style> after the shell's stylesheet, and within a shared | ||
| * `@layer utilities` the later-source rule wins. Result: the |
Comment on lines
+9
to
+22
| * css-injected-by-js, that reset would apply to every element on | ||
| * the page — including the shell's chrome. Symptom: sidebar/header | ||
| * borders disappear, layout shifts. Fix: import only `theme` and | ||
| * `utilities`, never the full `tailwindcss` entry. The shell ships | ||
| * its own Preflight once for the whole page. | ||
| * | ||
| * 2) Cascade order on shared utilities (`.hidden`, `.flex`, `.block`). | ||
| * Tailwind 4 emits only the utilities each project actually uses. | ||
| * The shell uses `hidden md:block` (shadcn sidebar) but a module | ||
| * typically does not — so the shell's stylesheet contains BOTH | ||
| * `.hidden` and `.md\:block`, while the module's stylesheet | ||
| * contains ONLY `.hidden`. css-injected-by-js appends the module's | ||
| * <style> after the shell's stylesheet, and within a shared | ||
| * `@layer utilities` the later-source rule wins. Result: the |
Addresses Copilot review on PR #17 — the comment referred to the plugin as `css-injected-by-js` while the actual package is `vite-plugin-css-injected-by-js`. Standardizes on the full name so the comment is greppable against package.json / vite.config.ts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@copilot review |
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
data-statetoexpandedbut the sidebar element stayeddisplay: none. Reproduced live infront-scholarship-funds(fix shipped there: corabank/front-scholarship-funds#1).@layer utilities.module-utilities) so the shell's responsive utilities (.md\:block,.md\:flex, etc) win regardless of<style>injection order.What changed
src/styles/globals.css:The top-of-file comment is expanded to document this gotcha alongside the existing Preflight one — so devs cloning the template don't have to rediscover it.
Why this is the right fix
Tailwind 4 emits only the utilities each project actually uses. The shell uses
hidden md:block(shadcn sidebar), so the shell's CSS has both.hiddenand.md\:block. A typical module doesn't usemd:block, so the module's CSS has only.hidden.vite-plugin-css-injected-by-jsappends the module's<style>after the shell's stylesheet, and inside a shared@layer utilitiesthe later source-order rule wins — so the module's.hiddendefeats the shell's.md\:blockat any viewport width.Splitting into a lower-priority
module-utilitieslayer makes the shell's utilities win on collision via layer order (not source order), which is exactly the contract we want: the shell owns chrome, the module styles its own content.Manual utilities a module adds later via
@layer utilities { ... }still go to the high-priority globalutilitieslayer — module-only selectors (e.g. customgradient-*utilities) keep their precedence over anything the shell might one day define with the same name.Test plan
npm install,npm run build— should succeed unchanged.data-stateon[data-slot="sidebar"]transitions correctly betweencollapsed↔expanded.front-scholarship-funds(done in linked PR) and verify side-by-side.Related
🤖 Generated with Claude Code