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:
import { createContext, useContext, useEffect, useState } from "react";
type Theme = "dark" | "light" | "system";
const ThemeProviderContext = createContext({
export function ThemeProvider({
const [theme, setTheme] = useState(defaultTheme);
const savedTheme = localStorage.getItem(storageKey);
if (savedTheme) setTheme(savedTheme);
document.documentElement.classList.remove("light", "dark");
if (theme === "system") {
document.documentElement.classList.add(
window.matchMedia("(prefers-color-scheme: dark)").matches
document.documentElement.classList.add(theme);
<ThemeProviderContext.Provider value={{ theme, setTheme }}>
</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.
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";
} from "@/components/ui/dropdown-menu";
export function ThemeToggle() {
const { setTheme } = useTheme();
<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" />
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
<DropdownMenuItem onClick={() => setTheme("dark")}>
<DropdownMenuItem onClick={() => setTheme("system")}>
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);
const checkIfMobile = () => setIsMobile(window.innerWidth < 768);
window.addEventListener("resize", checkIfMobile);
return () => window.removeEventListener("resize", checkIfMobile);
✔ 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
- Install
tailwindcss@latest:
npm install tailwindcss@latest
- 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.
- Run the Tailwind upgrade tool to detect breaking changes:
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! 🚀