Skip to content

useTheme ​

Composable for managing theme and color mode preferences.

Live Demo ​

Current: navy dark

Basic Usage ​

vue
<script setup>
const { theme, mode, setTheme, setMode } = useTheme();
</script>

Changing Themes ​

vue
<template>
  <div>
    <h2>Choose Theme</h2>
    <orio-button variant="secondary" @click="setTheme('navy')">
      Navy
    </orio-button>
    <orio-button variant="secondary" @click="setTheme('teal')">
      Teal
    </orio-button>
    <orio-button variant="secondary" @click="setTheme('forest')">
      Forest
    </orio-button>
    <orio-button variant="secondary" @click="setTheme('wine')">
      Wine
    </orio-button>
    <orio-button variant="secondary" @click="setTheme('royal')">
      Royal
    </orio-button>
    <orio-button variant="secondary" @click="setTheme('violet')">
      Violet
    </orio-button>

    <p>Current theme: {{ theme }}</p>
  </div>
</template>

<script setup>
const { theme, setTheme } = useTheme();
</script>

Changing Color Mode ​

vue
<template>
  <orio-button variant="secondary" @click="toggleMode">
    {{ mode === "dark" ? "☀️ Light" : "🌙 Dark" }}
  </orio-button>
</template>

<script setup>
const { mode, setMode } = useTheme();

function toggleMode() {
  setMode(mode.value === "dark" ? "light" : "dark");
}
</script>

Return Values ​

PropertyTypeDescription
themeRef<string>Current accent theme name
modeRef<string>Current color mode ('light' or 'dark')
setTheme(name: string) => voidFunction to change accent theme
setMode(mode: string) => voidFunction to change color mode

Built-in Themes ​

The library includes five built-in themes that you can use out of the box:

Deep blue professional theme

Teal ​

Fresh cyan/turquoise theme

Forest ​

Natural green theme

Wine ​

Rich burgundy/red theme

Royal ​

Vibrant blue theme

Persistence ​

Theme preferences are automatically saved to localStorage:

  • orio-theme - Stores accent theme
  • orio-mode - Stores color mode

Preferences are restored on page load.

SSR Compatibility ​

The composable handles SSR gracefully:

  • localStorage operations only run on client
  • DOM updates are wrapped in typeof document !== 'undefined' checks
  • Theme is applied on mount

Examples ​

Theme Switcher Component ​

vue
<template>
  <div class="theme-switcher">
    <select v-model="currentTheme" @change="handleThemeChange">
      <option value="navy">Navy</option>
      <option value="teal">Teal</option>
      <option value="forest">Forest</option>
      <option value="wine">Wine</option>
      <option value="royal">Royal</option>
      <option value="violet">Violet</option>
    </select>

    <orio-button variant="secondary" @click="toggleDarkMode">
      {{ isDark ? "Light Mode" : "Dark Mode" }}
    </orio-button>
  </div>
</template>

<script setup>
const { theme, mode, setTheme, setMode } = useTheme();

const currentTheme = computed({
  get: () => theme.value,
  set: (val) => setTheme(val),
});

const isDark = computed(() => mode.value === "dark");

function handleThemeChange() {
  // Theme already updated via v-model
  console.log("Theme changed to:", theme.value);
}

function toggleDarkMode() {
  setMode(isDark.value ? "light" : "dark");
}
</script>

Settings Page ​

vue
<template>
  <div class="settings">
    <h2>Appearance Settings</h2>

    <div class="setting-group">
      <label>Color Theme</label>
      <div class="theme-options">
        <orio-button
          v-for="t in themes"
          :key="t.value"
          variant="secondary"
          :class="{ active: theme === t.value }"
          @click="setTheme(t.value)"
        >
          {{ t.label }}
        </orio-button>
      </div>
    </div>

    <div class="setting-group">
      <label>Mode</label>
      <div class="mode-toggle">
        <orio-button
          variant="secondary"
          :class="{ active: mode === 'light' }"
          @click="setMode('light')"
        >
          ☀️ Light
        </orio-button>
        <orio-button
          variant="secondary"
          :class="{ active: mode === 'dark' }"
          @click="setMode('dark')"
        >
          🌙 Dark
        </orio-button>
      </div>
    </div>
  </div>
</template>

<script setup>
const { theme, mode, setTheme, setMode } = useTheme();

const themes = [
  { label: "Navy", value: "navy" },
  { label: "Teal", value: "teal" },
  { label: "Forest", value: "forest" },
  { label: "Wine", value: "wine" },
  { label: "Royal", value: "royal" },
  { label: "Violet", value: "violet" },
];
</script>

Custom Themes ​

The theming system is fully customizable. You can override existing themes or create entirely new ones by defining CSS variables in your own stylesheets.

Understanding Theme Variables ​

Themes control the accent colors used throughout the UI. The main variables you can customize are:

css
:root[data-theme="your-theme"] {
  --color-accent: /* Main accent color */ --color-accent-soft:
    /* Light background tint */
    --color-accent-border: /* Border color */;
}

The --color-accent-ink, --color-accent-hover, and --color-accent-active are automatically derived using color-mix().

Creating a New Theme ​

Define your theme in your app's CSS:

css
/* In your main CSS file or a separate theme file */
:root[data-theme="sunset"] {
  --color-accent: hsl(16 90% 48%);
  --color-accent-soft: hsl(16 100% 96%);
  --color-accent-border: hsl(16 85% 80%);
}

:root[data-theme="ocean"] {
  --color-accent: hsl(199 89% 48%);
  --color-accent-soft: hsl(199 100% 96%);
  --color-accent-border: hsl(199 75% 80%);
}

:root[data-theme="lavender"] {
  --color-accent: hsl(267 65% 58%);
  --color-accent-soft: hsl(267 100% 97%);
  --color-accent-border: hsl(267 50% 85%);
}

Then use them in your app:

vue
<script setup>
const { setTheme } = useTheme();

// Use your custom theme
setTheme("sunset");
</script>

Overriding Built-in Themes ​

You can completely override any built-in theme by redefining its variables:

css
/* Override the "navy" theme with your brand colors */
:root[data-theme="navy"] {
  --color-accent: #0066cc; /* Your brand blue */
  --color-accent-soft: #e6f2ff;
  --color-accent-border: #99ccff;
}

Complete Custom Theme Example ​

Here's a full example with multiple custom themes:

css
/* bright-pink.css */
:root[data-theme="bright-pink"] {
  --color-accent: hsl(328 100% 54%);
  --color-accent-soft: hsl(328 100% 97%);
  --color-accent-border: hsl(328 73% 84%);
}

:root[data-theme="mint"] {
  --color-accent: hsl(162 63% 41%);
  --color-accent-soft: hsl(162 60% 96%);
  --color-accent-border: hsl(162 40% 80%);
}

:root[data-theme="amber"] {
  --color-accent: hsl(38 92% 50%);
  --color-accent-soft: hsl(38 100% 96%);
  --color-accent-border: hsl(38 100% 82%);
}
vue
<template>
  <div>
    <orio-button variant="secondary" @click="setTheme('bright-pink')"
      >Bright Pink</orio-button
    >
    <orio-button variant="secondary" @click="setTheme('mint')"
      >Mint</orio-button
    >
    <orio-button variant="secondary" @click="setTheme('amber')"
      >Amber</orio-button
    >
  </div>
</template>

<script setup>
const { setTheme } = useTheme();
</script>

Dark Mode Considerations ​

Custom themes automatically work with dark mode. The library handles dark mode adjustments using the data-mode attribute. You only need to define the base accent colors.

If you want to customize how your theme looks in dark mode specifically:

css
:root[data-mode="dark"][data-theme="sunset"] {
  /* Optional: override specific values for dark mode */
  --color-accent-soft: hsl(16 30% 15%);
  --color-accent-border: hsl(16 40% 25%);
}

Tips for Creating Themes ​

  1. Use HSL values for easier color manipulation
  2. Keep sufficient contrast between accent and soft/border variants
  3. Test in both light and dark modes to ensure readability
  4. Soft variants should be very light (90-97% lightness in HSL for light mode)
  5. Border variants should be between soft and accent in intensity (75-85% lightness)