This repo is a demonstration of how to support theme selection in JavaScript-disabled environments, allowing the user to select light, dark, or system-preferred theme.
This utilizes (experimental) remote forms, instead of form actions, to set a cookie with which the server is able to appropriately assign a class to force light or dark mode if not wanting to follow system preference.
No event listeners are manually added and no media queries are performed manually; almost all of the magic happens with a multi-rule custom dark variant for Tailwind:
@custom-variant dark {
@media (prefers-color-scheme: dark) {
&:not(:is(.theme-light, .theme-light *)) {
@slot;
}
}
&:is(.theme-dark, .theme-dark *) {
@slot;
}
}
The server can assign the .theme-light or .theme-dark class during initial render,
natively supporting JS-disabled clients, and the only extra bit necessary to get it
working in JS-enabled clients is a single $state that is updated through
the enhanced form after submit.
Note: There are two ways of selecting theme in JS-enabled environments:
/settings page (with a submit button)select dropdown in the footer (without a submit button)That select element renders as disabled in JS-disabled environments, mainly because
it uses JS to automatically submit on change to avoid having a big button next to it.