DEV Community

Cover image for Type-Safe Design Tokens in Vue: Introducing TokiForge v1.1.0
Sachin Dilshan
Sachin Dilshan

Posted on

Type-Safe Design Tokens in Vue: Introducing TokiForge v1.1.0

If you've ever worked with design tokens in Vue, you know the pain of losing type safety. You define your tokens with a specific structure, but when you access them in components, TypeScript treats them as a generic DesignTokens type. No autocomplete, no type checking, and plenty of opportunities for typos.

TokiForge v1.1.0 solves this problem by introducing type-safe token access for Vue developers. In this post, we'll explore how this feature works, why it matters, and how to use it in your projects.

The Problem: Losing Type Information

Before v1.1.0, when you used useTheme() in Vue, you'd get back a ComputedRef<DesignTokens>. While this works, it's not very helpful:

// Before v1.1.0
const { tokens } = useTheme();

// TypeScript only knows it's DesignTokens
// No autocomplete for token paths
// No type checking for token structure
tokens.value.color.primary // ❌ TypeScript doesn't know if this exists
Enter fullscreen mode Exit fullscreen mode

This means:

  • ❌ No IntelliSense/autocomplete
  • ❌ No compile-time type checking
  • ❌ Easy to make typos in token paths
  • ❌ No refactoring support

The Solution: Generic Type Parameters

TokiForge v1.1.0 introduces generic type support to useTheme() and provideTheme(). Now you can specify your exact token type and get full type safety:

// v1.1.0 - Type-safe!
const { tokens } = useTheme<MyDesignTokens>();

// Full autocomplete and type checking! βœ…
tokens.value.color.primary.value // TypeScript knows this exists
Enter fullscreen mode Exit fullscreen mode

Getting Started

Installation

npm install @tokiforge/core @tokiforge/vue
Enter fullscreen mode Exit fullscreen mode

Define Your Token Type

First, define your token structure as a TypeScript interface:

import type { DesignTokens, TokenValue } from '@tokiforge/core';

interface MyDesignTokens extends DesignTokens {
  color: {
    primary: TokenValue;
    secondary: TokenValue;
    background: {
      default: TokenValue;
      muted: TokenValue;
    };
  };
  radius: {
    sm: TokenValue;
    md: TokenValue;
    lg: TokenValue;
  };
  spacing: {
    xs: TokenValue;
    sm: TokenValue;
    md: TokenValue;
    lg: TokenValue;
  };
}
Enter fullscreen mode Exit fullscreen mode

Create Your Tokens

const lightTokens: MyDesignTokens = {
  color: {
    primary: { value: '#7C3AED', type: 'color' },
    secondary: { value: '#06B6D4', type: 'color' },
    background: {
      default: { value: '#FFFFFF', type: 'color' },
      muted: { value: '#F9FAFB', type: 'color' },
    },
  },
  radius: {
    sm: { value: '4px', type: 'dimension' },
    md: { value: '8px', type: 'dimension' },
    lg: { value: '12px', type: 'dimension' },
  },
  spacing: {
    xs: { value: '4px', type: 'dimension' },
    sm: { value: '8px', type: 'dimension' },
    md: { value: '16px', type: 'dimension' },
    lg: { value: '24px', type: 'dimension' },
  },
};

const darkTokens: MyDesignTokens = {
  color: {
    primary: { value: '#A78BFA', type: 'color' },
    secondary: { value: '#22D3EE', type: 'color' },
    background: {
      default: { value: '#0F172A', type: 'color' },
      muted: { value: '#1E293B', type: 'color' },
    },
  },
  radius: {
    sm: { value: '4px', type: 'dimension' },
    md: { value: '8px', type: 'dimension' },
    lg: { value: '12px', type: 'dimension' },
  },
  spacing: {
    xs: { value: '4px', type: 'dimension' },
    sm: { value: '8px', type: 'dimension' },
    md: { value: '16px', type: 'dimension' },
    lg: { value: '24px', type: 'dimension' },
  },
};
Enter fullscreen mode Exit fullscreen mode

Provide Theme with Type Safety

<script setup lang="ts">
import { provideTheme } from '@tokiforge/vue';

const themeConfig = {
  themes: [
    { name: 'light', tokens: lightTokens },
    { name: 'dark', tokens: darkTokens },
  ],
  defaultTheme: 'light',
};

// Type is automatically inferred from config!
provideTheme(themeConfig);
</script>
Enter fullscreen mode Exit fullscreen mode

Use Theme with Type Safety

<script setup lang="ts">
import { useTheme } from '@tokiforge/vue';

// Specify your token type for full type safety
const { tokens, setTheme } = useTheme<MyDesignTokens>();

// Now you get full autocomplete! πŸŽ‰
const primaryColor = tokens.value.color.primary.value;
const borderRadius = tokens.value.radius.lg.value;
const spacing = tokens.value.spacing.md.value;
</script>

<template>
  <div>
    <button
      :style="{
        backgroundColor: tokens.value.color.primary.value,
        borderRadius: tokens.value.radius.lg.value,
        padding: tokens.value.spacing.md.value,
      }"
      @click="setTheme('dark')"
    >
      Switch Theme
    </button>
  </div>
</template>
Enter fullscreen mode Exit fullscreen mode

Real-World Example

Here's a complete example showing how type-safe tokens work in a real component:

<template>
  <div class="card" :style="cardStyles">
    <h2 :style="headingStyles">Type-Safe Tokens</h2>
    <p :style="textStyles">
      This component uses type-safe design tokens with full IntelliSense support.
    </p>
    <button :style="buttonStyles" @click="toggleTheme">
      Current Theme: {{ theme }}
    </button>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useTheme } from '@tokiforge/vue';
import type { DesignTokens, TokenValue } from '@tokiforge/core';

interface AppDesignTokens extends DesignTokens {
  color: {
    primary: TokenValue;
    secondary: TokenValue;
    text: {
      primary: TokenValue;
      secondary: TokenValue;
    };
    background: {
      default: TokenValue;
      card: TokenValue;
    };
  };
  radius: {
    sm: TokenValue;
    md: TokenValue;
    lg: TokenValue;
  };
  spacing: {
    sm: TokenValue;
    md: TokenValue;
    lg: TokenValue;
  };
}

const { theme, tokens, setTheme } = useTheme<AppDesignTokens>();

const cardStyles = computed(() => ({
  backgroundColor: tokens.value.color.background.card.value,
  borderRadius: tokens.value.radius.md.value,
  padding: tokens.value.spacing.lg.value,
}));

const headingStyles = computed(() => ({
  color: tokens.value.color.text.primary.value,
  marginBottom: tokens.value.spacing.md.value,
}));

const textStyles = computed(() => ({
  color: tokens.value.color.text.secondary.value,
  marginBottom: tokens.value.spacing.md.value,
}));

const buttonStyles = computed(() => ({
  backgroundColor: tokens.value.color.primary.value,
  color: '#FFFFFF',
  borderRadius: tokens.value.radius.sm.value,
  padding: `${tokens.value.spacing.sm.value} ${tokens.value.spacing.md.value}`,
  border: 'none',
  cursor: 'pointer',
}));

const toggleTheme = () => {
  setTheme(theme.value === 'light' ? 'dark' : 'light');
};
</script>
Enter fullscreen mode Exit fullscreen mode

Benefits of Type-Safe Tokens

1. IntelliSense/Autocomplete

Your IDE now knows exactly what tokens are available:

tokens.value.color. // IDE suggests: primary, secondary, text, background
tokens.value.radius. // IDE suggests: sm, md, lg
Enter fullscreen mode Exit fullscreen mode

2. Compile-Time Type Checking

TypeScript will catch errors before runtime:

// ❌ TypeScript error: Property 'invalid' does not exist
tokens.value.color.invalid.value;

// βœ… TypeScript knows this is valid
tokens.value.color.primary.value;
Enter fullscreen mode Exit fullscreen mode

3. Refactoring Support

When you rename tokens, your IDE can refactor all usages automatically.

4. Better Documentation

The type definition serves as documentation for your token structure.

Type Inference

You don't always need to explicitly specify the type. TokiForge can infer it from your config:

const config = {
  themes: [
    { name: 'light', tokens: lightTokens },
    { name: 'dark', tokens: darkTokens },
  ],
  defaultTheme: 'light',
};

// Type is automatically inferred!
const context = provideTheme(config);
// context.tokens is now typed based on your token structure
Enter fullscreen mode Exit fullscreen mode

Backward Compatibility

All existing code continues to work without changes. If you don't specify a type parameter, it defaults to DesignTokens:

// Still works - defaults to DesignTokens
const { tokens } = useTheme();
Enter fullscreen mode Exit fullscreen mode

This means you can migrate gradually, adding type safety where it matters most.

Migration Guide

Migrating to type-safe tokens is straightforward:

Step 1: Define Your Token Type

Create an interface that extends DesignTokens:

interface MyDesignTokens extends DesignTokens {
  // Your token structure
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Update Your Token Definitions

Add type annotations to your token objects:

const lightTokens: MyDesignTokens = {
  // Your tokens
};
Enter fullscreen mode Exit fullscreen mode

Step 3: Use Generic Type Parameter

Update your useTheme() calls:

// Before
const { tokens } = useTheme();

// After
const { tokens } = useTheme<MyDesignTokens>();
Enter fullscreen mode Exit fullscreen mode

That's it! Your code now has full type safety.

Advanced Usage

Extracting Token Types

You can extract the token type from your config:

import type { ExtractTokenType } from '@tokiforge/vue';

type Config = {
  themes: Array<{ name: string; tokens: MyDesignTokens }>;
  defaultTheme?: string;
};

type InferredTokens = ExtractTokenType<Config & ThemeConfig>;
Enter fullscreen mode Exit fullscreen mode

Multiple Token Types

If you have different token structures for different parts of your app:

interface ComponentTokens extends DesignTokens {
  button: {
    primary: TokenValue;
    secondary: TokenValue;
  };
}

const { tokens } = useTheme<ComponentTokens>();
Enter fullscreen mode Exit fullscreen mode

Performance

Type safety comes with zero runtime overhead. The generic types are purely compile-time features:

  • βœ… No runtime performance impact
  • βœ… Still <3KB gzipped
  • βœ… Uses CSS variables for instant theme switching
  • βœ… SSR-friendly

What's Next?

Type-safe token access is currently available for Vue. We're planning to extend this to:

  • React: Type-safe useTheme() hook
  • Svelte: Type-safe createThemeStore()
  • Angular: Type-safe theme service

If you're interested in contributing, we'd love your help! Check out our roadmap for more details.

Conclusion

Type-safe design tokens in TokiForge v1.1.0 bring the full power of TypeScript to your design system. With autocomplete, type checking, and better developer experience, building type-safe design systems has never been easier.

Try it out today:

npm install @tokiforge/core @tokiforge/vue
Enter fullscreen mode Exit fullscreen mode

Resources:

Have questions or feedback? Drop a comment below or open an issue on GitHub!

Top comments (0)