To implement a dark/light mode toggle in Vue 3 with TypeScript and CSS, you can follow these steps. This approach will use Vue’s reactive properties, TypeScript support, and CSS classes for styling.
Steps to Implement Dark/Light Mode
- Set Up a Global Dark Mode State: Use Vue’s
reactive
to store the mode state. - Toggle Dark Mode: Use a method to toggle between dark and light modes.
- Apply Dark Mode Styling: Use conditional CSS classes to apply dark mode styles.
- Persist the Mode: Optionally, save the mode in
localStorage
so it persists across page reloads.
Implementation
Here’s the complete setup:
Step 1: Define the Dark Mode State in a Composable
You can create a composable for managing the dark mode state.
typescriptCopy code// composables/useDarkMode.ts
import { ref, watchEffect } from 'vue';
const darkMode = ref<boolean>(false);
export function useDarkMode() {
// Load dark mode preference from localStorage (optional)
darkMode.value = localStorage.getItem('darkMode') === 'true';
const toggleDarkMode = () => {
darkMode.value = !darkMode.value;
localStorage.setItem('darkMode', darkMode.value.toString());
};
// Watch for changes in darkMode and update the document body class
watchEffect(() => {
if (darkMode.value) {
document.body.classList.add('dark-mode');
} else {
document.body.classList.remove('dark-mode');
}
});
return { darkMode, toggleDarkMode };
}
Step 2: Create a Dark/Light Mode Toggle Component
Create a button to toggle the mode in a component.
vueCopy code<!-- components/DarkModeToggle.vue -->
<template>
<button @click="toggleDarkMode">
{{ darkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode' }}
</button>
</template>
<script lang="ts" setup>
import { useDarkMode } from '../composables/useDarkMode';
const { darkMode, toggleDarkMode } = useDarkMode();
</script>
<style scoped>
button {
cursor: pointer;
padding: 0.5rem 1rem;
font-size: 1rem;
}
</style>
Step 3: Add Dark Mode Styles in CSS
Define dark and light mode styles using CSS. You can apply a global class, such as dark-mode
, to control theme styling.
cssCopy code/* styles.css (or any global CSS file) */
body {
--background-color: #ffffff;
--text-color: #000000;
background-color: var(--background-color);
color: var(--text-color);
}
body.dark-mode {
--background-color: #121212;
--text-color: #ffffff;
}
Step 4: Integrate in Your App Component
Use the toggle component in your app and add the CSS to your main file.
vueCopy code<!-- App.vue -->
<template>
<div>
<DarkModeToggle />
<p>This is a sample text to demonstrate dark mode.</p>
</div>
</template>
<script lang="ts" setup>
import DarkModeToggle from './components/DarkModeToggle.vue';
</script>
<style src="./styles.css"></style>
Step 5: Import Global Styles
Ensure that styles.css
is imported in your main.ts
or App.vue
so that the dark mode styles are applied globally.
typescriptCopy code// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import './styles.css'; // Import the global styles
createApp(App).mount('#app');
Explanation of Key Parts
- Composable (
useDarkMode
): Manages dark mode state and syncs it withlocalStorage
. - Toggle Component (
DarkModeToggle.vue
): Renders a button to toggle dark mode. - CSS Variables: Define colors as variables, making it easy to switch between light and dark mode by changing the values.
- Global CSS Class (
.dark-mode
): Applied to the<body>
when dark mode is enabled, allowing global theming across the app.
Optional: Advanced – System Preference Detection
To detect the system’s preferred color scheme and apply it on initial load, add this to your useDarkMode
composable:
typescriptCopy code// Set initial state based on system preference if no localStorage value exists
if (localStorage.getItem('darkMode') === null) {
darkMode.value = window.matchMedia('(prefers-color-scheme: dark)').matches;
}
This setup provides a responsive dark/light mode implementation that persists across sessions and is easily managed across your Vue 3 app.
To implement a dark/light mode toggle in Vue 3 with TypeScript and CSS, we can follow these steps:
- Define a global theme state (either using
ref
or acomputed
property). - Set up CSS variables to define the color schemes for dark and light modes.
- Apply classes on the main
App.vue
element to switch between dark and light themes. - Persist the user’s preference using
localStorage
(optional).
Here’s a step-by-step implementation:
Step 1: Set Up the Theme State
Define a reactive state to toggle between dark and light themes. This can be done in a store (like with pinia
or vuex
), or directly within your App.vue
.
typescriptCopy code// src/composables/useTheme.ts
import { ref, onMounted } from 'vue';
export function useTheme() {
const theme = ref<'light' | 'dark'>('light');
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
document.documentElement.className = theme.value;
localStorage.setItem('theme', theme.value);
};
onMounted(() => {
const savedTheme = localStorage.getItem('theme') as 'light' | 'dark' | null;
if (savedTheme) {
theme.value = savedTheme;
document.documentElement.className = savedTheme;
}
});
return { theme, toggleTheme };
}
Step 2: Apply CSS Variables for Themes
Define CSS variables for dark and light modes in your CSS. This example shows how to do it in App.vue
with scoped styles.
cssCopy code/* src/App.css */
:root {
--bg-color: #ffffff;
--text-color: #000000;
}
.dark {
--bg-color: #1e1e1e;
--text-color: #ffffff;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
}
These variables allow you to change styles dynamically based on the theme class (.dark
or .light
) on the <html>
or <body>
element.
Step 3: Create a Toggle Button in Your Component
In App.vue
, add a button to toggle between dark and light modes.
htmlCopy code<!-- src/App.vue -->
<template>
<div>
<button @click="toggleTheme">Toggle Theme</button>
<p>Current theme: {{ theme }}</p>
<!-- Other components and content here -->
</div>
</template>
<script lang="ts" setup>
import { useTheme } from './composables/useTheme';
const { theme, toggleTheme } = useTheme();
</script>
<style scoped>
@import './App.css';
</style>
Step 4: Use the CSS Variables in Other Components
When styling components, you can now use the CSS variables, and they’ll automatically adjust based on the selected theme.
For example:
htmlCopy code<!-- src/components/MyComponent.vue -->
<template>
<div class="my-component">
<p>This text will adapt to dark and light themes.</p>
</div>
</template>
<style scoped>
.my-component {
background-color: var(--bg-color);
color: var(--text-color);
}
</style>
Additional Tips
- Detect System Preference: You can also use the
window.matchMedia
API to detect the system’s color scheme on initial load. - CSS Transitions: Add transitions to color properties for smoother switching:cssCopy code
body { transition: background-color 0.3s ease, color 0.3s ease; }
With this approach, you can easily switch between dark and light modes in a Vue 3 + TypeScript app with CSS styling.