Nuxt 3
@theme-kit/nuxt
Nuxt 3 module with SSR-first theming, zero-flash bootstrap, cookie sync, config-driven transitions, custom scrollbar, and auto-imported composables.
Installation
Install the package for your framework alongside @theme-kit/core.
pnpm add @theme-kit/nuxtQuick Start
Start from scratch — install the package, then wrap your app in the provider at the entry point shown below.
1import { themes } from "./themes";
2
3export default defineNuxtConfig({
4 modules: ["@theme-kit/nuxt"],
5 themeKit: {
6 themes,
7 defaultTheme: "mint-light",
8 initialMode: "system",
9 transition: { duration: 360, easing: "cubic-bezier(0.4, 0, 0.2, 1)" },
10 scrollbar: true,
11 },
12});@theme-kit/core surface, so history, batching, snapshots, packs and lifecycle work the same way across frameworks.Implementation
Read and update theme state from any component using the framework-native primitives below.
1export default defineNuxtConfig({
2 modules: ["@theme-kit/nuxt"],
3 themeKit: {
4 themes,
5 defaultTheme: "mint-light",
6 initialMode: "system",
7 },
8});What's Available
@theme-kit/nuxt ships 12 exports in 4 categories. Everything below is also documented in the full API reference. Click any export to reveal what it does and how to use it.
Server
Client
Transition
Scrollbar
Use Cases
The important features in practice — copy any of these straight into your app.
Add the module
Register the module and configure themes in nuxt.config.
1// nuxt.config.ts
2export default defineNuxtConfig({
3 modules: ["@theme-kit/nuxt"],
4 themeKit: {
5 themes,
6 defaultTheme: "mint-light",
7 initialMode: "system",
8 },
9});SSR-first theming
Cookies are validated (fingerprint) and the initial theme is resolved and rendered server-side with a blocking bootstrap — no flash of the wrong theme.
1// nuxt.config.ts
2export default defineNuxtConfig({
3 modules: ["@theme-kit/nuxt"],
4 themeKit: {
5 themes,
6 defaultTheme: "mint-light",
7 initialMode: "system",
8 initialFamily: "mint",
9 },
10});
11
12// The module emits, before first paint:
13// <html data-theme="mint-light" data-theme-mode="light" data-theme-family="mint">
14// <style>:root{--background:…}</style>
15// <script>/* blocking bootstrap */</script>Auto-imported composables
useTheme and friends are auto-imported in every component.
1<script setup>
2const { theme, mode, setMode, toggleTheme } = useTheme();
3</script>
4
5<template>
6 <button @click="toggleTheme">{{ theme.name }} · {{ mode }}</button>
7 <button @click="setMode('dark')">Dark</button>
8</template>Components + runtime access
ThemeScope, ThemeScrollbar and the runtime are available everywhere.
1<script setup>
2const runtime = useThemeRuntime();
3function soften() {
4 runtime.update({ radius: { sm: 8, md: 12 } });
5}
6</script>
7
8<template>
9 <ThemeScope theme="forest-light">
10 <DataViz />
11 </ThemeScope>
12 <ThemeScrollbar auto-hide />
13 <button @click="soften">Soften corners</button>
14</template>Runtime access in a plugin
The plugin-provided runtime is available as `nuxtApp.$themeKit`.
1// plugins/theme.client.ts
2export default defineNuxtPlugin((nuxtApp) => {
3 const runtime = nuxtApp.$themeKit as ThemeRuntime;
4 runtime.lifecycle.on("beforeThemeChange", (e) => {
5 console.log("theme changed to", e.next.name);
6 });
7});Smooth theme transitions
Enable config-driven CSS transitions on theme changes.
1// nuxt.config.ts
2export default defineNuxtConfig({
3 modules: ["@theme-kit/nuxt"],
4 themeKit: {
5 themes,
6 defaultTheme: "light",
7 transition: { enabled: true, duration: 360, easing: "cubic-bezier(0.4, 0, 0.2, 1)" },
8 },
9});More Examples
Scoped theming, history controls, and framework-specific patterns.
1// nuxt.config.ts
2export default defineNuxtConfig({
3 modules: ["@theme-kit/nuxt"],
4 themeKit: {
5 themes,
6 defaultTheme: "mint-light",
7 initialMode: "system",
8 initialFamily: "mint",
9 transition: { duration: 300, easing: "ease" },
10 scrollbar: true,
11 },
12});
13
14// components/ThemeSwitcher.vue
15<script setup>
16// useTheme, useThemeRuntime, ThemeScope and ThemeScrollbar
17// are auto-imported by the module — no imports needed.
18const { theme, mode, family, setMode, setFamily, toggleTheme } = useTheme();
19</script>
20
21<template>
22 <button @click="toggleTheme">Toggle</button>
23 <button @click="setFamily('forest')">Forest</button>
24
25 <ThemeScope theme="forest-light">
26 <p>Scoped to forest-light</p>
27 </ThemeScope>
28
29 <ThemeScrollbar auto-hide />
30</template>API Reference
Server
| Export | Description |
|---|---|
SSR-first theme resolution | Reads `theme-name`, `theme-mode`, `theme-family`, `theme-fingerprint` cookies, validates the fingerprint, resolves the initial theme, and renders `<html data-theme>` with inline CSS variables before hydration. |
Blocking bootstrap script | Emits a blocking script in `<head>` that applies the persisted theme before first paint. |
Dark-mode CSS fallback | Emits `@media (prefers-color-scheme: dark)` styles when the persisted mode is `system`. |
Cookie + localStorage sync | The client mirrors selection back to cookies so the server renders the right theme on the next request — same contract as `@theme-kit/next`. |
Client
| Export | Description |
|---|---|
Runtime plugin | A Nuxt plugin installs one app-wide runtime, provided to `useTheme()`, `useThemeRuntime()` and every auto-imported composable. |
Auto-imports | Composables (`useTheme`, `useThemeMode`, `useThemeFamily`, `useThemeHistory`, …) and components (`ThemeScope`, `ThemeScrollbar`) are registered automatically — no manual imports. |
configKey: "themeKit" | Configure `themes`, `defaultTheme`, `initialMode`, `initialFamily`, `transition`, `scrollbar`, `storageKey` and `scheduled` in `nuxt.config.ts`. |
useThemeSchedule() | Auto-imported composable exposing the sunrise/sunset schedule: reactive `state` (`enabled`, `status`, `sunrise`, `sunset`, `nextTransition`) plus `enable()`/`disable()`/`set()`. Configure via `scheduled` in the module config. |
Transition
| Export | Description |
|---|---|
transition in nuxt.config.ts | Configure `transition` in the `themeKit` config object to enable CSS transitions on theme changes. Duration/easing are set once; Theme Kit generates the transition styles at runtime. |
runtime.store.set(theme, { suppressTransition: true }) | Per-update escape hatch: `runtime.store.set(theme, { suppressTransition: true })` skips the configured animation. For custom animation orchestration, compose the core diff/plan/runner APIs. |
Scrollbar
| Export | Description |
|---|---|
scrollbar: true | Enables Theme Kit's custom overlay scrollbar. The SSR bootstrap hides the native scrollbar before first paint, then the overlay engine synchronizes with browser scrolling without replacing native scroll behavior. |
scrollbar option | Configure the overlay appearance (thickness, radius, colors, auto-hide, …) from the `themeKit` config; the overlay stays theme-aware and updates with runtime theme changes. |