Guide
React, Vue, Svelte and a plain page
React — no provider
import { ThemeToggle, useTheme } from '@devix-labs/theme-toggle/react';
import '@devix-labs/theme-toggle/styles.css';
function Header() {
return <ThemeToggle labels />;
}
function Anywhere() {
const { theme, resolved, setTheme, toggle } = useTheme();
return <button onClick={toggle}>Currently {resolved}</button>;
}
There is no <ThemeProvider> to wrap your app in, because there is nothing to
provide: the theme lives on the document, which every component can already see.
That absence is worth being explicit about, because two of the open issues on the alternative are consequences of having one — nested providers and forcing a theme on one route. Neither question arises here.
The anti-flash snippet goes in app/layout.tsx or _document, as a plain
string — not a component:
import { antiFlashScript } from '@devix-labs/theme-toggle';
export default function RootLayout({ children }) {
return (
<html suppressHydrationWarning>
<head>
<script dangerouslySetInnerHTML={{ __html: antiFlashScript() }} />
</head>
<body>{children}</body>
</html>
);
}
Better still, generate it once at build time and paste the 564 bytes in — then React never sees it at all, which is exactly what #349 asks for.
Vue
<script setup>
import { onMounted, onBeforeUnmount, ref } from 'vue';
import { themeToggle } from '@devix-labs/theme-toggle/vue';
import '@devix-labs/theme-toggle/styles.css';
const host = ref(null);
let toggle;
onMounted(() => { toggle = themeToggle(host.value, { labels: true }); });
onBeforeUnmount(() => toggle?.destroy());
</script>
<template><div ref="host" /></template>
Svelte
<script>
import { themeToggle } from '@devix-labs/theme-toggle/svelte';
import '@devix-labs/theme-toggle/styles.css';
</script>
<div use:themeToggle={{ variant: 'button' }} />
A web component
<script type="module" src="https://devix.pk/cdn/oss/theme-toggle@1.0.0/element.js"></script>
<dx-theme variant="segmented" labels></dx-theme>
Attributes: variant, themes, storage-key, attribute, labels,
no-system. It exposes .theme and fires change with
{ choice, resolved }.
Laravel and Blade
The snippet is a string, so a Blade layout is the easiest case of all:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<script>{!! $antiFlash !!}</script>
@vite('resources/css/app.css')
</head>
<body>
<div id="theme"></div>
@vite('resources/js/app.js')
</body>
</html>
Generate $antiFlash once and cache it — it never changes unless your options
do:
$antiFlash = Cache::rememberForever('theme.script', fn () => file_get_contents(
public_path('build/theme-snippet.js')
));
Astro, Eleventy, Hugo, plain HTML
<head>
<script>(function(){try{/* … */}catch(e){}})();</script>
</head>
Run antiFlashScript() once, in a Node script, and commit the output. It is 564
bytes and it changes only when your themes or storage key do — so there is no
reason for it to be a runtime dependency at all.