# How to Implement Theming and Design Tokens in Native SDK Applications

> Discover how to implement theming and design tokens in Native SDK applications. Leverage the lightweight theming system for real-time color scheme and design token switching.

- Repository: [Vercel Labs/native](https://github.com/vercel-labs/native)
- Tags: how-to-guide
- Published: 2026-07-18

---

**The Native SDK runtime provides a lightweight theming system that enables real-time switching between light/dark color schemes and complete design-token packs using the `LivePreview` class in [`docs/src/lib/live-preview.ts`](https://github.com/vercel-labs/native/blob/main/docs/src/lib/live-preview.ts).**

Theming and design tokens in Native SDK applications are handled by a dual-axis system that combines color schemes with interchangeable token registers. According to the vercel-labs/native source code, this architecture allows you to re-style entire interfaces instantly without rebuilding scenes or re-rendering JavaScript components.

## Understanding the Theming Architecture

The Native SDK theming engine operates on two distinct primitives that work together to control the visual appearance of your application.

### Theme Schemes (Light/Dark)

The **Scheme** axis controls overall brightness using a binary light/dark toggle. When you call the engine API `preview_set_theme(handle, dark)`, the canvas immediately redraws using the appropriate color values from the current token register while maintaining all layout and component structure.

### Theme Packs (Design Tokens)

A **theme pack** is a self-contained register of design tokens—including palettes, control tables, and type scales—that replaces the entire design system definition. The engine API `preview_set_theme_pack(handle, namePtr, nameLen)` validates the pack name and applies the new token register across the whole preview. Because the Native SDK stores token data on the engine side, no JavaScript re-rendering occurs; the canvas simply redraws with the new values.

## Working with the LivePreview API

The high-level `LivePreview` class wraps the low-level WebAssembly engine calls, exposing convenient methods for runtime theme manipulation.

### Toggling Color Schemes

To switch between light and dark modes, use the `setTheme` method on your `LivePreview` instance:

```typescript
import { PreviewEngine, LivePreview } from "./live-preview";

// Initialize engine (wasm instance loaded elsewhere)
const engine = new PreviewEngine(wasmExports);
const preview = engine.create(`...your Native markup...`, false);

// Toggle dark mode
function toggleDarkMode(isDark: boolean) {
  preview.setTheme(isDark);
}

// Switch to dark scheme
toggleDarkMode(true);

```

This method maps directly to the engine's `preview_set_theme` function, triggering an immediate canvas redraw with the scheme-appropriate colors from the active token pack.

### Switching Theme Packs

To replace the entire design token set, call `setThemePack` with one of the built-in pack identifiers:

```typescript
import { themePacks, ThemePack } from "./live-preview";

// Apply a different token pack
function applyThemePack(pack: ThemePack) {
  preview.setThemePack(pack);
}

// Switch to the "geist" design system
applyThemePack("geist");

```

The built-in packs are defined as a constant array in [`docs/src/lib/live-preview.ts`](https://github.com/vercel-labs/native/blob/main/docs/src/lib/live-preview.ts) at lines 55-61:

```typescript
export const themePacks = ["house", "geist"] as const;
export type ThemePack = (typeof themePacks)[number];

```

## Complete Implementation Example

Here is a complete workflow demonstrating dynamic theme switching with UI controls:

```typescript
import { PreviewEngine, LivePreview, themePacks, ThemePack } from "./live-preview";

// Initialise the preview engine
const engine = new PreviewEngine(wasmExports);
const preview = engine.create(`...your Native markup...`, false);
if (!preview) throw new Error("Failed to create preview");

// Toggle light/dark scheme
function toggleDarkMode(isDark: boolean) {
  preview.setTheme(isDark);
}

// Switch design-token packs
function applyThemePack(pack: ThemePack) {
  preview.setThemePack(pack);
}

// Example: Cycle through packs on button click
let currentPack: ThemePack = "house";
document.getElementById("themeBtn")?.addEventListener("click", () => {
  currentPack = currentPack === "house" ? "geist" : "house";
  applyThemePack(currentPack);
});

// Initial state
toggleDarkMode(true);
applyThemePack("geist");

```

## Extending with Custom Theme Packs

While the Native SDK ships with `house` and `geist` packs, you can add custom theme packs by registering them in the engine's Zig source code. Once compiled into the engine, custom packs are referenced by their manifest-facing name using the same `setThemePack` method. The engine validates the pack name against available registers before applying the new token set, ensuring type-safe theme management across your application.

## Summary

- **Theme schemes** control light/dark brightness via `preview.setTheme(isDark)`, mapped to `preview_set_theme` in the engine.
- **Theme packs** are complete design-token registers accessible via `preview.setThemePack(pack)`, using the built-in `"house"` and `"geist"` constants defined in [`docs/src/lib/live-preview.ts`](https://github.com/vercel-labs/native/blob/main/docs/src/lib/live-preview.ts).
- **Live re-theming** occurs instantly on the engine side without JavaScript re-rendering, requiring only a canvas redraw.
- **Custom packs** can be added through Zig source compilation and referenced identically to built-in packs.

## Frequently Asked Questions

### What is a theme pack in the Native SDK?

A theme pack is a self-contained register of design tokens—including color palettes, spacing values, typography scales, and control tables—that defines a complete design system. According to the source code in [`docs/src/lib/live-preview.ts`](https://github.com/vercel-labs/native/blob/main/docs/src/lib/live-preview.ts), packs like `"house"` and `"geist"` are stored on the engine side and swapped instantly via the `preview_set_theme_pack` API without requiring scene rebuilds.

### How do I switch between light and dark modes?

Use the `setTheme` method on your `LivePreview` instance, passing a boolean where `true` indicates dark mode. This wraps the low-level `preview_set_theme` engine API and triggers an immediate canvas redraw using the current theme pack's color values for the selected scheme.

### Can I create custom theme packs?

Yes. Custom theme packs are implemented by adding new token registers to the engine's Zig source code. Once compiled, these packs are referenced by name using the same `setThemePack` method that handles built-in packs, allowing you to extend the Native SDK with your own design systems.

### Where are the built-in theme packs defined?

The built-in theme packs are declared as a TypeScript constant array in [`docs/src/lib/live-preview.ts`](https://github.com/vercel-labs/native/blob/main/docs/src/lib/live-preview.ts) at lines 55-61. The current implementation exports `themePacks = ["house", "geist"]` with a corresponding `ThemePack` type, which provides IntelliSense and compile-time validation when calling `setThemePack`.