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
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
Getting Started
Installation
npm install @tokiforge/core @tokiforge/vue
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;
};
}
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' },
},
};
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>
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>
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>
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
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;
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
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();
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
}
Step 2: Update Your Token Definitions
Add type annotations to your token objects:
const lightTokens: MyDesignTokens = {
// Your tokens
};
Step 3: Use Generic Type Parameter
Update your useTheme() calls:
// Before
const { tokens } = useTheme();
// After
const { tokens } = useTheme<MyDesignTokens>();
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>;
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>();
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
Resources:
- π Documentation
- π» GitHub Repository
- π Report Issues
- π¬ Discussions
Have questions or feedback? Drop a comment below or open an issue on GitHub!
Top comments (0)