A simple way to toggle light and dark mode in a Svelte application.
What is dark mode?
When enabled on a website, dark mode (also “night mode”) reduces the amount of light emitted by a screen by changing the palette of colours it uses. For instance, changing the background from a paper-white to a dark gray, and text colour from black to light gray.
Dark mode can be more comfortable to use in low-light conditions. Some technologies, such as OLED panels, may consume less power which is better suited for mobile devices.
Our goal?
We want a component that allows the user to change between light and dark mode. Third party components should also be notified of the colour mode.
Method
We specify a dark style in our application stylesheet. When triggered,
we manipulate
Element.classList
on <body>
to add or remove this class. We use a Svelte
store
to track the change, which allows third-party components to alter their
rendering.
The CSS
A very simple implementation of the CSS required may look like (say static/styles.css
):
.light {
background: #eee;
color: #121212;
}
.dark {
background: #121212;
color: #aaa;
}
The store
We track the selected mode in our store, say store.js
:
import { writable } from 'svelte/store';
export const colourScheme = writable('light');
The component
A <select>
element allows the user to switch between modes. We bind
to $colourScheme
so any subscribers will get notification of the change
(say ./ColourScheme.svelte
):
<script>
import { colourScheme } from './store.js';
const schemes = [ 'light', 'dark' ];
$: {
document.body.classList.remove(...schemes);
document.body.classList.add($colourScheme);
}
</script>
<select bind:value={$colourScheme}>
{#each schemes as s}
<option value={s}>{s}</option>
{/each}
</select>
Usage
Include the component wherever it’s required:
<script>
import ColourScheme from './ColourScheme.svelte';
</script>
<ColourScheme />
An implementation can be seen on this website, at the top of the page.
Summary
We created a component that allows the user to choose between two colour modes, specified in CSS. The chosen colour mode is stored in a Svelte store, available to other subscribed components.
Improvements
- Some applications may require extending light / dark mode to a generic “theme” mode, where selection from a number of palettes can be performed by the user. Extending the above solution would be trivial for this case.
- The solution demonstrated above ignores the CSS media prefers-color-scheme. At a minimum, the default selection for the mode chooser should adhere to the value of this feature.
- SvelteKit performs server-side rendering of the
application, so
document
is not available and the reference to it in the above example will fail. This should be guarded bybrowser
from$app/env
. More details here.