Skip to content

fix: attach window.matchMedia listener for OS-level dark mode changes#438

Merged
Junman140 merged 2 commits into
Pi-Defi-world:devfrom
ZEMAD0N26:fix/dark-mode-listener
May 30, 2026
Merged

fix: attach window.matchMedia listener for OS-level dark mode changes#438
Junman140 merged 2 commits into
Pi-Defi-world:devfrom
ZEMAD0N26:fix/dark-mode-listener

Conversation

@ZEMAD0N26
Copy link
Copy Markdown

@ZEMAD0N26 ZEMAD0N26 commented May 29, 2026

closes #348

Summary by CodeRabbit

Release Notes

  • New Features

    • Added dark mode theme support with automatic detection of system preferences.
    • Added style isolation for third-party widgets to prevent styling conflicts.
  • Bug Fixes

    • Fixed right-to-left (RTL) language layout support for page headers.
    • Resolved stylesheet merge conflicts and syntax errors.

Review Change Stack

@drips-wave
Copy link
Copy Markdown

drips-wave Bot commented May 29, 2026

@ZEMAD0N26 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Warning

Review limit reached

@Junman140, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 57 minutes and 4 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 15e7eb85-3f67-411f-98d4-28045c5604e0

📥 Commits

Reviewing files that changed from the base of the PR and between 0d257f8 and b3817fc.

📒 Files selected for processing (1)
  • app/layout.tsx
📝 Walkthrough

Walkthrough

The PR introduces dark mode theme support and third-party widget style isolation. CSS rules establish an isolated .widget-isolate container using all: initial and all: revert. The root layout imports ThemeProvider, adds a nonce-protected script to detect system dark mode preference and toggle the dark class, and wraps the application content to enable theme context.

Changes

Theme and Widget Isolation Infrastructure

Layer / File(s) Summary
Widget style isolation and RTL utilities
app/globals.css
The .widget-isolate CSS class resets wrapper and descendant styles to isolate third-party widgets. Merge conflict artifacts are cleaned up and the RTL utilities block is syntactically completed with [dir='rtl'] .page-header-row rule.
Dark mode theme provider and detection script
app/layout.tsx
The layout imports ThemeProvider and restructures the document tree to wrap content inside it. An inline script with nonce protection is injected into <head> to detect prefers-color-scheme: dark and toggle the document dark class; suppressHydrationWarning is added to the <html> element.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 A rabbit's delight in dark mode's sweet sight,
Widgets now nestled in isolation's tight,
With all: initial we start clean and pure,
The theme script ensures your preference's secure! 🌙✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the primary change: attaching a window.matchMedia listener for OS-level dark mode changes, which directly addresses the linked issue #348.
Linked Issues check ✅ Passed The code changes implement the required functionality: adding a window.matchMedia listener in app/layout.tsx to detect OS-level dark mode changes and update the theme accordingly.
Out of Scope Changes check ✅ Passed CSS changes in app/globals.css for widget isolation and the ThemeProvider integration in app/layout.tsx are aligned with dark mode theme management objectives; no unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/layout.tsx`:
- Around line 101-106: The media query handling currently registers only
mql.addEventListener('change', updateTheme) and never applies the initial theme,
which breaks in Safari and causes a flash; update the logic around mql and
updateTheme so you: (1) immediately call updateTheme with the current matches
(e.g., invoke updateTheme({matches: mql.matches}) or call updateTheme directly
using mql.matches) to sync theme right away, and (2) add a backwards-compatible
listener by falling back to mql.addListener(updateTheme) when addEventListener
is not available (keep using mql.addEventListener when present), referencing the
existing mql and updateTheme identifiers and ensuring
document.documentElement.classList.toggle('dark', ...) is used by updateTheme.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a9207ed8-046b-4c8c-8da1-0b4e3b826e7b

📥 Commits

Reviewing files that changed from the base of the PR and between 8b1c4d1 and 0d257f8.

📒 Files selected for processing (2)
  • app/globals.css
  • app/layout.tsx

Comment thread app/layout.tsx
Comment on lines +101 to +106
const mql = window.matchMedia('(prefers-color-scheme: dark)');
function updateTheme(e) {
document.documentElement.classList.toggle('dark', e.matches);
}
mql.addEventListener('change', updateTheme);
} catch (err) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the browser support status for MediaQueryList.addEventListener('change') vs MediaQueryList.addListener, especially on Safari/iOS versions still commonly in use?

💡 Result:

The MediaQueryList.addEventListener('change',...) method is the modern, standards-compliant approach for monitoring media query changes [1][2], while MediaQueryList.addListener(...) is deprecated [1][3]. Browser Support Summary: 1. MediaQueryList.addEventListener('change'): Supported in Safari since version 14 (on both macOS and iOS) [2][4]. If your project needs to support Safari 13 or earlier, this method will be undefined, and attempting to call it will throw an error [4]. 2. MediaQueryList.addListener: A legacy alias that was used before MediaQueryList inherited from EventTarget [1][5]. It is supported in older Safari versions where addEventListener is missing [2][5]. Recommendation for Compatibility: To support both modern browsers and older versions of Safari (specifically Safari 13 and below), use a feature detection pattern. Check for the existence of addEventListener before falling back to the deprecated addListener [4][6]: const mql = window.matchMedia('(prefers-color-scheme: dark)'); if (mql.addEventListener) { // Modern browsers (Safari 14+, Chrome, Firefox, etc.) mql.addEventListener('change', callback); } else if (mql.addListener) { // Legacy support (Safari 13 and older) mql.addListener(callback); } This approach ensures your code utilizes the modern EventTarget interface where available while maintaining functionality on older, legacy browsers that are still encountered in the wild [4][6].

Citations:


Sync theme immediately and add MediaQueryList fallback for Safari

  • The block only uses mql.addEventListener('change', ...); Safari 13 and earlier may not support addEventListener on MediaQueryList, and the surrounding try/catch will silently prevent listener hookup.
  • The script never applies the initial mql.matches, so it can mismatch/flash until the rest of the theme logic runs.
Suggested patch
               (function() {
                 try {
                   const mql = window.matchMedia('(prefers-color-scheme: dark)');
-                  function updateTheme(e) {
-                    document.documentElement.classList.toggle('dark', e.matches);
+                  function updateTheme(target) {
+                    document.documentElement.classList.toggle('dark', target.matches);
                   }
-                  mql.addEventListener('change', updateTheme);
+                  updateTheme(mql);
+                  if (typeof mql.addEventListener === 'function') {
+                    mql.addEventListener('change', updateTheme);
+                  } else if (typeof mql.addListener === 'function') {
+                    mql.addListener(updateTheme);
+                  }
                 } catch (err) {}
               })();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/layout.tsx` around lines 101 - 106, The media query handling currently
registers only mql.addEventListener('change', updateTheme) and never applies the
initial theme, which breaks in Safari and causes a flash; update the logic
around mql and updateTheme so you: (1) immediately call updateTheme with the
current matches (e.g., invoke updateTheme({matches: mql.matches}) or call
updateTheme directly using mql.matches) to sync theme right away, and (2) add a
backwards-compatible listener by falling back to mql.addListener(updateTheme)
when addEventListener is not available (keep using mql.addEventListener when
present), referencing the existing mql and updateTheme identifiers and ensuring
document.documentElement.classList.toggle('dark', ...) is used by updateTheme.

@Junman140 Junman140 merged commit 5041fcb into Pi-Defi-world:dev May 30, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

window.matchMedia('(prefers-color-scheme: dark)') listener not attached – L

2 participants