-
-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Added polyfill for TailwindCSS v4 migration #25062
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
ref https://linear.app/ghost/issue/PROD-2642/upgrade-tailwindcss-to-v4 This PR is part of migrating to TailwindCSS v4 in reasonable small chunks. The core idea is that first we'd update the classnames according to the [TWCSS v4 upgrade guide](https://tailwindcss.com/docs/upgrade-guide) without actually changing TWCSS to v4. This would mean that we'd need a (seemingly small) CSS file that adds classes in v3 that exist in v4 (but not in v3). It allows us to update Shade and app classes one app at a time and once that's done we can update TWCSS to v4 and all classes would be already up to date by then. This PR is the first step in this: it creates temporary CSS utilities to support TailwindCSS v4 classnames while maintaining v3 compatibility. This polyfill includes: - shadow-xs, drop-shadow-xs (v4 shadow scale) - blur-xs, backdrop-blur-xs (v4 blur scale) - rounded-xs (v4 border radius scale) - outline-hidden (v4 outline utility) The polyfill will be removed after upgrading to TailwindCSS v4.
WalkthroughAdds a new CSS file (apps/shade/src/styles/tailwind-v4-polyfill.css) defining temporary utility classes to emulate Tailwind v4-specific utilities: .shadow-xs, .drop-shadow-xs, .blur-xs, .backdrop-blur-xs, .rounded-xs, and .outline-hidden. Updates apps/shade/styles.css to import this polyfill after Tailwind base/components/utilities, with a comment noting its temporary nature. No other files or logic are changed. Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/shade/styles.css (1)
7-8
: Import looks good; consider@layer utilities
in the polyfill (or move import).Current placement after Tailwind is fine, especially if the polyfill wraps rules in
@layer utilities
. Alternatively, import it before@import "tailwindcss/utilities";
to let Tailwind handle ordering.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/shade/src/styles/tailwind-v4-polyfill.css
(1 hunks)apps/shade/styles.css
(1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
PR: TryGhost/Ghost#0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-09-11T11:56:37.466Z
Learning: Applies to apps/shade/src/ShadeApp.tsx : Scope Tailwind styles to .shade (and use .dark for dark mode) within the app wrapper
📚 Learning: 2025-09-11T11:56:37.466Z
Learnt from: CR
PR: TryGhost/Ghost#0
File: apps/shade/AGENTS.md:0-0
Timestamp: 2025-09-11T11:56:37.466Z
Learning: Applies to apps/shade/src/ShadeApp.tsx : Scope Tailwind styles to .shade (and use .dark for dark mode) within the app wrapper
Applied to files:
apps/shade/src/styles/tailwind-v4-polyfill.css
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Admin-X Settings tests
- GitHub Check: ActivityPub tests
- GitHub Check: Unit tests (Node 22.13.1)
- GitHub Check: Build & Push
.shadow-xs { | ||
box-shadow: 0 0 1px rgba(0,0,0,0.04), 0 1px 3px rgba(0,0,0,0.03), 0 8px 10px -12px rgba(0,0,0,.1); | ||
} | ||
|
||
/* Drop shadow utilities */ | ||
.drop-shadow-xs { | ||
filter: drop-shadow(0 1px 1px rgb(0 0 0 / 0.05)); | ||
} | ||
|
||
/* Blur utilities */ | ||
.blur-xs { | ||
filter: blur(2px); | ||
} | ||
|
||
/* Backdrop blur utilities */ | ||
.backdrop-blur-xs { | ||
backdrop-filter: blur(2px); | ||
} | ||
|
||
/* Border radius utilities */ | ||
.rounded-xs { | ||
border-radius: 0.125rem; /* 2px */ | ||
} | ||
|
||
/* Outline utilities */ | ||
.outline-hidden { | ||
outline: 2px solid transparent; | ||
outline-offset: 2px; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Adopt Tailwind variable-based composition, add Safari prefix, and scope to .shade
.
Direct box-shadow/filter/backdrop-filter clobbers Tailwind’s ring/filter stacks and can break combined utilities. Also missing -webkit-backdrop-filter
. Scope under .shade
per Shade scoping practice. Wrap in @layer utilities
for correct ordering/purge.
Please also verify the numeric values match Tailwind v4 tokens for exact visual parity.
Apply this diff:
-/* Shadow utilities */
-.shadow-xs {
- box-shadow: 0 0 1px rgba(0,0,0,0.04), 0 1px 3px rgba(0,0,0,0.03), 0 8px 10px -12px rgba(0,0,0,.1);
-}
-
-/* Drop shadow utilities */
-.drop-shadow-xs {
- filter: drop-shadow(0 1px 1px rgb(0 0 0 / 0.05));
-}
-
-/* Blur utilities */
-.blur-xs {
- filter: blur(2px);
-}
-
-/* Backdrop blur utilities */
-.backdrop-blur-xs {
- backdrop-filter: blur(2px);
-}
-
-/* Border radius utilities */
-.rounded-xs {
- border-radius: 0.125rem; /* 2px */
-}
-
-/* Outline utilities */
-.outline-hidden {
- outline: 2px solid transparent;
- outline-offset: 2px;
-}
+@layer utilities {
+ /* Shadow utilities */
+ .shade .shadow-xs {
+ /* Keep value consistent with Tailwind v4's shadow-xs token */
+ --tw-shadow: 0 0 1px rgba(0,0,0,0.04), 0 1px 3px rgba(0,0,0,0.03), 0 8px 10px -12px rgba(0,0,0,0.1);
+ --tw-shadow-colored: 0 0 1px var(--tw-shadow-color), 0 1px 3px var(--tw-shadow-color), 0 8px 10px -12px var(--tw-shadow-color);
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
+ }
+
+ /* Drop shadow utilities */
+ .shade .drop-shadow-xs {
+ --tw-drop-shadow: drop-shadow(0 1px 1px rgb(0 0 0 / 0.05));
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+ }
+
+ /* Blur utilities */
+ .shade .blur-xs {
+ --tw-blur: blur(2px);
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
+ }
+
+ /* Backdrop blur utilities */
+ .shade .backdrop-blur-xs {
+ --tw-backdrop-blur: blur(2px);
+ -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
+ backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
+ }
+
+ /* Border radius utilities */
+ .shade .rounded-xs {
+ border-radius: 0.125rem; /* 2px */
+ }
+
+ /* Outline utilities */
+ .shade .outline-hidden {
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+ }
+}
Based on learnings
🏁 Script executed:
#!/bin/bash
set -e
echo "== Check @layer in polyfill =="
grep -R "@layer" -n apps/shade/src/styles/tailwind-v4-polyfill.css || echo "No @layer found"
echo -e "\n== Check -webkit-backdrop-filter =="
grep -R "webkit-backdrop-filter" -n apps/shade/src/styles/tailwind-v4-polyfill.css || echo "No -webkit-backdrop-filter found"
echo -e "\n== Check --tw- variables =="
grep -R -- "--tw-" -n apps/shade/src/styles/tailwind-v4-polyfill.css || echo "No --tw- variables found"
echo -e "\n== File head (1-50) =="
sed -n '1,50p' apps/shade/src/styles/tailwind-v4-polyfill.css
echo -e "\n== Search .shade in CSS dir =="
grep -R "\.shade" -n apps/shade/src/styles || echo "No .shade in CSS"
echo -e "\n== ShadeApp.tsx head (1-200) =="
sed -n '1,200p' apps/shade/src/ShadeApp.tsx
Length of output: 2102
Wrap utilities in @layer utilities
, scope to .shade
, and add Safari prefix
- tailwind-v4-polyfill.css currently defines standalone, unscoped utilities that override Tailwind’s stacking behavior.
- Wrap all rules in
@layer utilities
and prepend selectors with.shade
. - Replace raw shadows/filters with Tailwind
--tw-…
variables. - Include
-webkit-backdrop-filter
alongsidebackdrop-filter
. - Confirm numeric values match Tailwind v4 tokens for visual parity.
🤖 Prompt for AI Agents
In apps/shade/src/styles/tailwind-v4-polyfill.css around lines 5 to 33, the
utilities are global raw rules that should be wrapped in @layer utilities and
scoped to the .shade namespace; change each selector to be prefixed with .shade
(e.g. .shade .shadow-xs etc.), move all rules inside a single @layer utilities
block, replace raw shadow/filter/blur values with corresponding Tailwind CSS
custom properties (use --tw-shadow, --tw-drop-shadow, --tw-blur,
--tw-backdrop-blur and compose box-shadow/filter using those variables) ensure
numeric values match Tailwind v4 token equivalents, add -webkit-backdrop-filter
alongside backdrop-filter for Safari, and keep outline-hidden using the same
.shade scoping.
ref https://linear.app/ghost/issue/PROD-2642/upgrade-tailwindcss-to-v4
This PR is part of migrating to TailwindCSS v4 in reasonable small chunks. The core idea is that first we'd update the classnames according to the TWCSS v4 upgrade guide without actually changing TWCSS to v4. This would mean that we'd need a (seemingly small) CSS file that adds classes in v3 that exist in v4 (but not in v3). It allows us to update Shade and app classes one app at a time and once that's done we can update TWCSS to v4 and all classes would be already up to date by then.
This PR is the first step in this: it creates temporary CSS utilities to support TailwindCSS v4 classnames while maintaining v3 compatibility. This polyfill includes:
The polyfill will be removed after upgrading to TailwindCSS v4.