useTheme()

useTheme() provides a complete theme management system (the theme is decided by theme.mode in swift.config.json):

  • Persists the theme value to localStorage and restores it automatically on page refresh.
  • Writes the current theme to the html[data-theme] attribute so global CSS can switch style variables with [data-theme='dark'] selectors.
  • In auto mode, reads the system preference (prefers-color-scheme) and applies light or dark accordingly; resolvedTheme gives the actual current light/dark (auto also resolves to light / dark).
  • Only theme.mode: 'toggle' lets users switch (toggleTheme / setTheme take effect); in system / dark / light modes the theme is locked by the mode and both are no-ops.

useTheme() is registered unconditionally and safe to call in any theme.mode — outside toggle mode the switch methods are no-ops (the theme is locked by the mode).

Basic Usage

toggleTheme tri-state cycle (real theme)

加载中...

setTheme direct switch

加载中...
<script setup lang="ts">
const { theme, setTheme, toggleTheme } = useTheme()
</script>

<template>
  <!-- Display current theme -->
  <span>Current theme: {{ theme }}</span>

  <!-- Cycle through themes -->
  <button @click="toggleTheme">
    {{ theme === 'dark' ? 'Switch to Light' : 'Switch to Dark' }}
  </button>

  <!-- Set a specific theme -->
  <button @click="setTheme('light')">Light</button>
  <button @click="setTheme('dark')">Dark</button>
  <button @click="setTheme('auto')">Follow System</button>
</template>

Watch Theme Changes

const { theme } = useTheme()

watch(theme, (newTheme) => {
  console.log('Theme changed to', newTheme)
})

CSS Integration

data-theme + semantic tokens

加载中...

The framework controls global theme variables via the html[data-theme] attribute. Define CSS variables for each theme in app/assets/css/:

:root {
  --background: #ffffff;
  --foreground: #1f2937;
}

[data-theme='dark'] {
  --background: #0f172a;
  --foreground: #f1f5f9;
}

Return Values

NameTypeDescription
themeRef<'light' | 'dark' | 'auto'>The user-chosen theme state. Initial value derived from mode (system→auto / dark→dark / light→light / toggle→default)
resolvedThemeComputedRef<'light' | 'dark'>Actual current light/dark (auto resolves to the system preference). Switch logos / illustrations off this
mode'system' | 'toggle' | 'dark' | 'light'The site's theme mode (readonly, from the theme.mode config)
toggleStates2 | 3Switcher form (readonly). 3 = tri-state cycle / 2 = two-state
setTheme(t: 'light' | 'dark' | 'auto') => voidSet a specific theme, persisting to localStorage and updating html[data-theme]. Toggle mode only
toggleTheme() => voidCycle themes. Toggle mode only; tri-state auto→light→dark→auto (can return to auto) / two-state light↔dark

Notes

  • useTheme() state is globally shared — multiple calls return the same reactive reference; no state inconsistency to worry about.
  • toggleTheme / setTheme only take effect in theme.mode: 'toggle'; in other modes they are no-ops (the theme is locked by the mode, not user-changeable).
  • When you don't want to write your own switch button, use the framework's built-in SwThemeSwitch — it self-gates and renders only in toggle mode.
  • On initialization the saved theme is read from localStorage (toggle mode only); when none is saved, the initial value is derived from the mode.