useDarkMode Composable
Reactive dark mode toggle with system preference detection and localStorage persistence
Code
import { ref, watch, onMounted, onUnmounted } from 'vue';
type ThemeMode = 'light' | 'dark' | 'system';
export function useDarkMode(): {
isDark: Ref<boolean>;
themeMode: Ref<ThemeMode>;
toggleDarkMode: () => void;
setThemeMode: (mode: ThemeMode) => void;
} {
// Get stored theme mode or default to system
const themeMode = ref<ThemeMode>(
(localStorage.getItem('theme-mode') as ThemeMode) || 'system'
);
const isDark = ref(false);
let mediaQuery: MediaQueryList | null = null;
// Update dark mode based on theme mode and system preference
const updateDarkMode = () => {
__TOKEN_37__ (themeMode.value === 'system') {
isDark.value = window.matchMedia('(prefers-color-scheme: dark)').matches;
} else {
isDark.value = themeMode.value === 'dark';
}
// Apply to document
document.documentElement.classList.toggle('dark', isDark.value);
};
// Toggle dark/light mode
const toggleDarkMode = () => {
setThemeMode(isDark.value ? 'light' : 'dark');
};
// Set specific theme mode
const setThemeMode = (mode: ThemeMode) => {
themeMode.value = mode;
localStorage.setItem('theme-mode', mode);
updateDarkMode();
};
// Listen to system preference changes
const handleSystemChange = () => {
__TOKEN_42__ (themeMode.value === 'system') updateDarkMode();
};
onMounted(() => {
mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
mediaQuery.addEventListener('change', handleSystemChange);
updateDarkMode();
});
onUnmounted(() => {
__TOKEN_43__ (mediaQuery) {
mediaQuery.removeEventListener('change', handleSystemChange);
}
});
// Watch for theme mode changes
watch(themeMode, updateDarkMode);
return {
isDark,
themeMode,
toggleDarkMode,
setThemeMode
};
}
// Usage example
// const { isDark, toggleDarkMode, setThemeMode } = useDarkMode();
// toggleDarkMode(); // Switch between light/dark
// setThemeMode('system'); // Use system preference