JavaScript API

JavaScript and TypeScript API reference for Turbo Themes.

JavaScript API

Reference for the Turbo Themes JavaScript and TypeScript exports.

Installation

npm install turbo-themes

Exports

Theme IDs

import { themeIds } from 'turbo-themes';

console.log(themeIds);
// [
//   'catppuccin-mocha',
//   'catppuccin-macchiato',
//   'catppuccin-frappe',
//   'catppuccin-latte',
//   'dracula',
//   'github-dark',
//   'github-light',
//   'bulma-dark',
//   'bulma-light'
// ]

ThemeId Type

import type { ThemeId } from 'turbo-themes';

// Type is a union of all valid theme IDs
type ThemeId =
  | 'catppuccin-mocha'
  | 'catppuccin-macchiato'
  | 'catppuccin-frappe'
  | 'catppuccin-latte'
  | 'dracula'
  | 'github-dark'
  | 'github-light'
  | 'bulma-dark'
  | 'bulma-light';

// Use for type-safe theme selection
function setTheme(theme: ThemeId) {
  // TypeScript will error if invalid theme passed
}

Token Data

import tokens from 'turbo-themes/tokens.json';

// Access metadata
tokens.meta.themeIds; // string[]
tokens.meta.vendors; // string[]
tokens.meta.totalThemes; // number
tokens.meta.lightThemes; // number
tokens.meta.darkThemes; // number

// Access theme data
const mocha = tokens.themes['catppuccin-mocha'];
mocha.id; // 'catppuccin-mocha'
mocha.label; // 'Catppuccin Mocha'
mocha.vendor; // 'catppuccin'
mocha.appearance; // 'dark'
mocha.tokens; // Token values

Theme Switching Implementation

Basic Implementation

import { themeIds, type ThemeId } from 'turbo-themes';

const STORAGE_KEY = 'turbo-theme';
const DEFAULT_THEME: ThemeId = 'catppuccin-mocha';

function getStoredTheme(): ThemeId {
  const stored = localStorage.getItem(STORAGE_KEY);
  if (stored && themeIds.includes(stored as ThemeId)) {
    return stored as ThemeId;
  }
  return DEFAULT_THEME;
}

function setTheme(themeId: ThemeId): void {
  // Update CSS
  const link = document.getElementById('theme-css') as HTMLLinkElement;
  if (link) {
    link.href = `/css/themes/turbo/${themeId}.css`;
  }

  // Update data attribute
  document.documentElement.setAttribute('data-theme', themeId);

  // Persist
  localStorage.setItem(STORAGE_KEY, themeId);
}

// Initialize on page load
document.addEventListener('DOMContentLoaded', () => {
  setTheme(getStoredTheme());
});

With React

import { useState, useEffect, createContext, useContext } from 'react';
import { themeIds, type ThemeId } from 'turbo-themes';

interface ThemeContextType {
  theme: ThemeId;
  setTheme: (theme: ThemeId) => void;
  themes: readonly ThemeId[];
}

const ThemeContext = createContext<ThemeContextType | null>(null);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setThemeState] = useState<ThemeId>('catppuccin-mocha');

  useEffect(() => {
    const stored = localStorage.getItem('turbo-theme') as ThemeId;
    if (stored && themeIds.includes(stored)) {
      setThemeState(stored);
    }
  }, []);

  const setTheme = (newTheme: ThemeId) => {
    setThemeState(newTheme);
    localStorage.setItem('turbo-theme', newTheme);

    const link = document.getElementById('theme-css') as HTMLLinkElement;
    if (link) {
      link.href = `/css/themes/turbo/${newTheme}.css`;
    }
  };

  return (
    <ThemeContext.Provider value={{ theme, setTheme, themes: themeIds }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
}

With Vue

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { themeIds, type ThemeId } from 'turbo-themes';

const currentTheme = ref<ThemeId>('catppuccin-mocha');

function setTheme(theme: ThemeId) {
  currentTheme.value = theme;
  localStorage.setItem('turbo-theme', theme);

  const link = document.getElementById('theme-css') as HTMLLinkElement;
  if (link) {
    link.href = `/css/themes/turbo/${theme}.css`;
  }
}

onMounted(() => {
  const stored = localStorage.getItem('turbo-theme') as ThemeId;
  if (stored && themeIds.includes(stored)) {
    currentTheme.value = stored;
  }
});
</script>

<template>
  <select :value="currentTheme" @change="setTheme($event.target.value)">
    <option v-for="theme in themeIds" :key="theme" :value="theme">
      {{ theme }}
    </option>
  </select>
</template>

With Svelte

<script lang="ts">
  import { onMount } from 'svelte';
  import { themeIds, type ThemeId } from 'turbo-themes';

  let currentTheme: ThemeId = 'catppuccin-mocha';

  function setTheme(theme: ThemeId) {
    currentTheme = theme;
    localStorage.setItem('turbo-theme', theme);

    const link = document.getElementById('theme-css') as HTMLLinkElement;
    if (link) {
      link.href = `/css/themes/turbo/${theme}.css`;
    }
  }

  onMount(() => {
    const stored = localStorage.getItem('turbo-theme') as ThemeId;
    if (stored && themeIds.includes(stored)) {
      currentTheme = stored;
    }
  });
</script>

<select bind:value={currentTheme} on:change={() => setTheme(currentTheme)}>
  {#each themeIds as theme}
    <option value={theme}>{theme}</option>
  {/each}
</select>

Preventing Flash of Unstyled Content (FOUC)

Add this blocking script in your <head>:

<script>
  (function () {
    const STORAGE_KEY = 'turbo-theme';
    const DEFAULT = 'catppuccin-mocha';
    const VALID = [
      'catppuccin-mocha',
      'catppuccin-macchiato',
      'catppuccin-frappe',
      'catppuccin-latte',
      'dracula',
      'github-dark',
      'github-light',
      'bulma-dark',
      'bulma-light',
    ];

    let theme = localStorage.getItem(STORAGE_KEY) || DEFAULT;
    if (!VALID.includes(theme)) theme = DEFAULT;

    document.documentElement.setAttribute('data-theme', theme);

    const link = document.getElementById('theme-css');
    if (link && theme !== DEFAULT) {
      link.href = '/css/themes/turbo/' + theme + '.css';
    }
  })();
</script>

Utility Functions

Check if Theme is Dark

import tokens from 'turbo-themes/tokens.json';
import type { ThemeId } from 'turbo-themes';

function isDarkTheme(themeId: ThemeId): boolean {
  return tokens.themes[themeId].appearance === 'dark';
}

Get Theme by Vendor

import tokens from 'turbo-themes/tokens.json';

function getThemesByVendor(vendor: string) {
  return Object.values(tokens.themes).filter((theme) => theme.vendor === vendor);
}

// Get all Catppuccin themes
const catppuccinThemes = getThemesByVendor('catppuccin');

Get Light/Dark Themes

import tokens from 'turbo-themes/tokens.json';

const darkThemes = Object.values(tokens.themes)
  .filter((t) => t.appearance === 'dark')
  .map((t) => t.id);

const lightThemes = Object.values(tokens.themes)
  .filter((t) => t.appearance === 'light')
  .map((t) => t.id);

Next Steps