Skip to content

Comments

Theme toggle added#27

Open
MohanPrasathSece wants to merge 1 commit intokris70lesgo:mainfrom
MohanPrasathSece:x
Open

Theme toggle added#27
MohanPrasathSece wants to merge 1 commit intokris70lesgo:mainfrom
MohanPrasathSece:x

Conversation

@MohanPrasathSece
Copy link

@MohanPrasathSece MohanPrasathSece commented Oct 10, 2025

User description

Added a theme switcher to the navbar so you can quickly toggle between light and dark mode.
Where it lives: The button is in the navbar on both desktop and mobile.
Component:
src/components/theme-toggle.tsx
Used in:
src/components/nav.tsx
No flicker on load: The app now sets your theme before the page fully loads to avoid a brief “flash” of the wrong theme.
Implemented in:
src/app/layout.tsx
Remembers your choice: Your theme preference is saved, so it stays the same when you come back.


PR Type

Enhancement


Description

  • Added theme toggle component for light/dark mode switching

  • Implemented FOUC prevention with inline script in layout

  • Integrated theme toggle in both desktop and mobile navigation

  • Added localStorage persistence for theme preferences


Diagram Walkthrough

flowchart LR
  A["User clicks theme toggle"] --> B["ThemeToggle component"]
  B --> C["Update DOM classes"]
  B --> D["Save to localStorage"]
  E["Page load"] --> F["Inline script"]
  F --> G["Apply saved theme"]
  G --> H["Prevent FOUC"]
Loading

File Walkthrough

Relevant files
Enhancement
theme-toggle.tsx
New theme toggle component implementation                               

src/components/theme-toggle.tsx

  • Created new theme toggle component with light/dark mode switching
  • Implemented localStorage persistence for theme preferences
  • Added proper initialization from DOM state
  • Included accessible button with icons and labels
+48/-0   
nav.tsx
Integrated theme toggle in navigation                                       

src/components/nav.tsx

  • Imported and integrated ThemeToggle component
  • Added theme toggle to desktop navigation bar
  • Added theme toggle to mobile navigation menu
  • Included descriptive comments for theme toggle placement
+5/-0     
layout.tsx
FOUC prevention and theme initialization                                 

src/app/layout.tsx

  • Added suppressHydrationWarning to html element
  • Implemented inline script for FOUC prevention
  • Added theme detection from localStorage and system preferences
  • Applied theme classes before React hydration
+21/-2   

@qodo-free-for-open-source-projects

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Inline script CSP risk

Description: The inline script uses dangerouslySetInnerHTML and accesses localStorage/window without
feature-policy checks, which could be blocked in restrictive CSP or SSR contexts and may
require a nonce/hash-based CSP to avoid XSS risks.
layout.tsx [21-36]

Referred Code
<script
  dangerouslySetInnerHTML={{
    __html: `
    (function() {
      try {
        var stored = localStorage.getItem('theme');
        var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
        var theme = stored || (prefersDark ? 'dark' : 'light');
        var root = document.documentElement;
        if (theme === 'dark') root.classList.add('dark');
        else root.classList.remove('dark');
      } catch (e) {}
    })();
  `,
  }}
/>
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
No custom compliance provided

Follow the guide to enable custom compliance check.

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@MohanPrasathSece
Copy link
Author

I have added this theme toggle feature, go through it

@qodo-free-for-open-source-projects

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Use next-themes for theme management

Replace the custom theme-switching logic with the next-themes library. This
simplifies the implementation by removing the manual inline script for FOUC
prevention and direct DOM manipulation, resulting in more robust and
maintainable code.

Examples:

src/app/layout.tsx [21-36]
        <script
          dangerouslySetInnerHTML={{
            __html: `
            (function() {
              try {
                var stored = localStorage.getItem('theme');
                var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
                var theme = stored || (prefersDark ? 'dark' : 'light');
                var root = document.documentElement;
                if (theme === 'dark') root.classList.add('dark');

 ... (clipped 6 lines)
src/components/theme-toggle.tsx [7-26]
  const [theme, setTheme] = useState<"light" | "dark">("light");

  useEffect(() => {
    // Initialize from current DOM (set by inline script) or system
    const isDark = document.documentElement.classList.contains("dark");
    setTheme(isDark ? "dark" : "light");
  }, []);

  const toggle = () => {
    const next = theme === "dark" ? "light" : "dark";

 ... (clipped 10 lines)

Solution Walkthrough:

Before:

// src/app/layout.tsx
<html lang="en" suppressHydrationWarning>
  <body>
    <script
      dangerouslySetInnerHTML={{
        __html: `(function() {
          var theme = localStorage.getItem('theme') || 'light';
          document.documentElement.classList.add(theme);
        })()`,
      }}
    />
    {children}
  </body>
</html>

// src/components/theme-toggle.tsx
export default function ThemeToggle() {
  const [theme, setTheme] = useState("light");
  useEffect(() => {
    const isDark = document.documentElement.classList.contains("dark");
    setTheme(isDark ? "dark" : "light");
  }, []);

  const toggle = () => {
    const next = theme === "dark" ? "light" : "dark";
    document.documentElement.classList.toggle("dark", next === "dark");
    localStorage.setItem("theme", next);
  };
  // ...
}

After:

// src/app/layout.tsx
import { ThemeProvider } from 'next-themes';

<html lang="en" suppressHydrationWarning>
  <body>
    <ThemeProvider attribute="class">
      {children}
    </ThemeProvider>
  </body>
</html>

// src/components/theme-toggle.tsx
import { useTheme } from 'next-themes';

export default function ThemeToggle() {
  const { theme, setTheme } = useTheme();

  const toggle = () => {
    setTheme(theme === 'dark' ? 'light' : 'dark');
  };
  // ...
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies that the PR reinvents a common feature and proposes using a standard, robust library (next-themes) which would significantly simplify the code, improve maintainability, and is considered best practice.

High
Possible issue
Prevent UI flicker on load

To prevent a UI flicker on load, delay rendering the theme toggle button until
the component has mounted and the correct theme is determined on the client.

src/components/theme-toggle.tsx [7-13]

 const [theme, setTheme] = useState<"light" | "dark">("light");
+const [mounted, setMounted] = useState(false);
 
 useEffect(() => {
+  setMounted(true);
   // Initialize from current DOM (set by inline script) or system
   const isDark = document.documentElement.classList.contains("dark");
   setTheme(isDark ? "dark" : "light");
 }, []);
 
+if (!mounted) {
+  // a placeholder to avoid layout shift and hydration mismatch
+  return <div className="h-[34px] w-[78px] rounded-md border border-border" />;
+}
+
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies a UI flicker issue due to a mismatch between server-rendered and client-hydrated state, and proposes a standard and effective solution to fix it.

Medium
Use functional state update for reliability

Use a functional state update for setTheme in the toggle function to prevent
race conditions from rapid clicks and ensure reliable theme switching.

src/components/theme-toggle.tsx [15-26]

 const toggle = () => {
-  const next = theme === "dark" ? "light" : "dark";
-  setTheme(next);
+  setTheme((prevTheme) => {
+    const next = prevTheme === "dark" ? "light" : "dark";
 
-  const root = document.documentElement;
-  if (next === "dark") root.classList.add("dark");
-  else root.classList.remove("dark");
+    const root = document.documentElement;
+    if (next === "dark") root.classList.add("dark");
+    else root.classList.remove("dark");
 
-  try {
-    localStorage.setItem("theme", next);
-  } catch {}
+    try {
+      localStorage.setItem("theme", next);
+    } catch {}
+    return next;
+  });
 };
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential race condition with rapid clicks and proposes using a functional state update, which is a best practice for robustness.

Low
  • More

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant