Skip to content

Conversation

peterzimon
Copy link
Contributor

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:

- 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.

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.
@github-actions github-actions bot added the community [triage] Community features and bugs label Oct 6, 2025
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

Walkthrough

Adds 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)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the addition of a temporary CSS polyfill for migrating to TailwindCSS v4, which is the primary change in this pull request.
Description Check ✅ Passed The description clearly explains the rationale and scope of adding temporary TailwindCSS v4 utility classes to maintain v3 compatibility while incrementally upgrading, which matches the changes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch shade-tw4-polyfill

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📥 Commits

Reviewing files that changed from the base of the PR and between 0809cee and 39075e5.

📒 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

Comment on lines +5 to +33
.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;
}
Copy link
Contributor

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 alongside backdrop-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.

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

Labels

community [triage] Community features and bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant