Skip to main content
Home Site Logo
  • Home
  • Blog
  • Projects
  • Tools
  • Home
  • Blog
  • Projects
  • Tools

Enhancing My Website with a Theme Switcher and Accessibility Improvements

How I improved the accessibility and mobile experience of my Dungeons & Dragons Toolbox project by adding a theme switcher and refining the design.

4 min read

3/15/2025

accessibility

frontend

tailwindcss

theme-switcher

web-development

Introduction

One of the most important aspects of a good website is ensuring accessibility and user experience. In my latest update to Dungeons & Dragons Toolbox, I focused on implementing a theme switcher, improving mobile responsiveness, and refining the overall accessibility of my project.

I also introduced important pages to make navigation easier and ensure a seamless experience across different devices.

This blog post documents the major improvements I made and the challenges I faced while implementing them.

Adding a Theme Switcher

A theme switcher allows users to toggle between light, dark, and system-based themes, providing better visibility based on their preferences. I implemented this feature using React’s Context API to manage theme state across the application.

Implementation

I created a ThemeProvider component that stores the selected theme in localStorage and applies it to the website:

"use client";
import { createContext, useContext, useEffect, useState } from "react";
type Theme = "dark" | "light" | "system";
const ThemeProviderContext = createContext({
theme: "system",
setTheme: () => {},
});
export function ThemeProvider({
children,
defaultTheme = "system",
storageKey = "theme",
}) {
const [theme, setTheme] = useState(defaultTheme);
useEffect(() => {
const savedTheme = localStorage.getItem(storageKey);
if (savedTheme) setTheme(savedTheme);
}, [storageKey]);
useEffect(() => {
document.documentElement.classList.remove("light", "dark");
if (theme === "system") {
document.documentElement.classList.add(
window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light"
);
} else {
document.documentElement.classList.add(theme);
}
}, [theme]);
return (
<ThemeProviderContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeProviderContext.Provider>
);
}
export const useTheme = () => useContext(ThemeProviderContext);

This ensures that the theme persists between sessions and adapts to the user’s system settings when set to system mode.

Theme Toggle Button

To allow users to switch themes easily, I built a dropdown menu toggle:

import { Moon, Sun } from "lucide-react";
import { useTheme } from "@/components/theme-provider";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export function ThemeToggle() {
const { setTheme } = useTheme();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" aria-label="Toggle theme">
<Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}

Improving Mobile Responsiveness

Since most browser users access the web on mobile devices, I ensured that the design is fully responsive and adapts to different screen sizes.

Key Improvements

✔ Use of Tailwind’s Responsive Utilities: Improved layout handling for smaller screens.
✔ Implemented a Mobile Detection Hook: Used a custom React hook (useIsMobile.ts) to adjust UI behavior dynamically.

export function useIsMobile() {
const [isMobile, setIsMobile] = useState(false);
useEffect(() => {
const checkIfMobile = () => setIsMobile(window.innerWidth < 768);
checkIfMobile();
window.addEventListener("resize", checkIfMobile);
return () => window.removeEventListener("resize", checkIfMobile);
}, []);
return isMobile;
}

✔ Improved Accessibility Features:

  • Added skip links for keyboard navigation.
  • Ensured focus styles for better visibility.
  • Improved contrast ratios in dark mode.

Challenges Faced

🔹 Persisting the Theme Across Reloads:

  • Solution: Used localStorage to save the user’s selected theme.

🔹 Ensuring Proper Accessibility:

  • Solution: Verified contrast ratios and keyboard navigation support.

Tailwind CSS v4

With the recent release of Tailwind CSS v4, it introduces several major improvements that can enhance development workflows:

Key Changes in Tailwind CSS v4

✔ CSS Custom Properties for Colors: Tailwind now fully supports CSS custom properties for colors, making it easier to override themes dynamically.
✔ Smaller File Sizes: The build output has been optimized, reducing overall CSS file size.
✔ Updated Default Border Behavior: The default border color is now currentColor, meaning borders inherit text color by default.
✔ New Shorthand Classes: Introduction of new shorthand utilities to streamline class naming.
✔ Breaking Changes: Some older utilities and settings have been deprecated, requiring updates for compatibility.

How to Update Your Project to Tailwind CSS v4

  1. Install tailwindcss@latest:
Terminal window
npm install tailwindcss@latest
  1. Modify Tailwind Config:

Check the tailwind.config.ts file and update deprecated settings if necessary, I had to temporarly delete plugins: [import("tailwindcss-animate")], as it broke my upgrade process.

  1. Run the Tailwind upgrade tool to detect breaking changes:
Terminal window
npx tailwindcss upgrade

With Tailwind v4, performance is greatly improved while maintaining the flexibility that makes it such a powerful CSS framework.

Conclusion

With these enhancements, my website is now more accessible, visually appealing, and user-friendly across all devices. The theme switcher makes it adaptable to different viewing preferences, while mobile optimizations ensure a smooth experience for all users.

🔗 Check out the pull request: GitHub PR #78

🎲 Explore the updated site: Dungeons & Dragons Toolbox

These updates bring my project one step closer to being a fully-fledged D&D utility platform! 🚀

Table of Contents

  • Introduction
  • Adding a Theme Switcher
  • Implementation
  • Theme Toggle Button
  • Improving Mobile Responsiveness
  • Key Improvements
  • Challenges Faced
  • Tailwind CSS v4
  • Key Changes in Tailwind CSS v4
  • How to Update Your Project to Tailwind CSS v4
  • Conclusion
GitHub LinkedIn