npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@quefep/theme-kit

v1.2.0

Published

A cross-framework, framework-agnostic SDK for managing design tokens in modern web applications

Downloads

406

Readme

ThemeKit

Design tokens shouldn't be scattered across your codebase. ThemeKit gives you one place to define colors, typography, spacing—everything—and use them anywhere. React, Vue, Angular, vanilla JS. Doesn't matter.

Why ThemeKit?

If you've ever had to update a primary color in 47 different files, you know the pain. ThemeKit fixes that. Define your tokens once, use them everywhere, switch themes on the fly.

What you get:

  • Works with React, Vue, Angular, or plain JavaScript
  • Full TypeScript support (types are auto-generated)
  • Light/dark mode with persistence built in
  • CLI to spit out CSS variables, SCSS, TypeScript—whatever you need
  • Validation so your tokens stay consistent
  • Runtime alias resolution with circular reference protection (opt-in)
  • Prefetch + cache themes so switches stay instant

Install

npm install @quefep/theme-kit

Getting Started

1. Set up your tokens

Create a tokens.json (you can also pass a JS object or a map of theme names ➝ tokens straight into the config):

{
  "colors": {
    "primary": "#4A90E2",
    "secondary": "#50E3C2",
    "background": "#FFFFFF",
    "text": "#333333"
  },
  "typography": {
    "fontFamily": "Inter, sans-serif",
    "fontSize": {
      "sm": "12px",
      "md": "16px",
      "lg": "20px"
    }
  },
  "spacing": {
    "sm": "4px",
    "md": "8px",
    "lg": "16px"
  }
}

2. Initialize

import { ThemeKit } from '@quefep/theme-kit';
import tokens from './tokens.json';

const theme = new ThemeKit({
  defaultTheme: 'light',
  tokens,
});

3. Use it in your framework

React:

import { ThemeProvider, useTheme } from '@quefep/theme-kit/react';

function App() {
  return (
    <ThemeProvider theme={theme}>
      <MyButton />
    </ThemeProvider>
  );
}

function MyButton() {
  const { getToken } = useTheme();
  return (
    <button style={{ backgroundColor: getToken('colors.primary') }}>
      Click me
    </button>
  );
}

Vue:

import { createApp } from 'vue';
import { ThemeKitPlugin } from '@quefep/theme-kit/vue';

createApp(App).use(ThemeKitPlugin, { theme });
<template>
  <button :style="{ backgroundColor: primaryColor }">Click me</button>
</template>

<script setup>
import { useColor } from '@quefep/theme-kit/vue';
const primaryColor = useColor('primary');
</script>

Angular:

import { ThemeKitModule } from '@quefep/theme-kit/angular';

@NgModule({
  imports: [ThemeKitModule.forRoot({ theme })],
})
export class AppModule {}

Vanilla JS:

import { ThemeKit, createVanillaThemeKit } from '@quefep/theme-kit/vanilla';

const theme = new ThemeKit({ tokens });
const vanillaTheme = createVanillaThemeKit(theme);

document.body.style.backgroundColor = vanillaTheme.getColor('background');

Switching Themes

// Switch to dark mode
theme.switch('dark');

// Or pass custom tokens on the fly
theme.switch('custom', {
  colors: {
    primary: '#FF6B6B',
    background: '#1A1A1A',
  },
});

// Check what's active
console.log(theme.getCurrentTheme()); // 'dark'

In React:

function ThemeToggle() {
  const { currentTheme, switchTheme } = useTheme();
  
  return (
    <button onClick={() => switchTheme(currentTheme === 'light' ? 'dark' : 'light')}>
      {currentTheme === 'light' ? 'Go dark' : 'Go light'}
    </button>
  );
}

Token Aliases

Reference other tokens using curly braces. Keeps things DRY:

{
  "colors": {
    "blue500": "#4A90E2",
    "primary": "{colors.blue500}",
    "buttonBackground": "{colors.primary}"
  }
}

Aliases get resolved at build time or runtime—your call.

Enable runtime aliasing when you spin up ThemeKit:

const theme = new ThemeKit({
  tokens,
  aliasing: {
    enabled: true,
    maxDepth: 15,
  },
});

ThemeKit will validate references, prevent circular lookups, and cache the resolved map per theme.

Prefetch & Cache Themes

ThemeKit now caches resolved tokens and lets you warm them up ahead of time:

theme.prefetchThemes();          // prefetch everything
theme.prefetchThemes(['dark']);  // or target a subset

Combine this with the built-in cache to keep theme switches snappy even with massive token graphs.

Color Utilities

Built-in functions for color manipulation:

import { lighten, darken, alpha, mix, contrastRatio, readableOn } from '@quefep/theme-kit';

lighten('#4A90E2', 20);        // 20% lighter
darken('#4A90E2', 20);         // 20% darker
alpha('#4A90E2', 0.5);         // rgba with 50% opacity
mix('#4A90E2', '#FF6B6B', 50); // 50/50 blend
contrastRatio('#000', '#fff'); // WCAG contrast ratio
readableOn('#4A90E2');         // returns black or white for text

CLI

Generate token files in different formats:

# CSS variables
npx @quefep/theme-kit generate --format css

# SCSS with custom prefix
npx @quefep/theme-kit generate --format scss --prefix myapp

# TypeScript types
npx @quefep/theme-kit generate --format ts

# Resolve aliases before generating
npx @quefep/theme-kit generate --format css --resolve-aliases

# Validate your tokens
npx @quefep/theme-kit validate

# Compare two token files
npx @quefep/theme-kit diff tokens-v1.json tokens-v2.json

# Start a new project
npx @quefep/theme-kit init --template basic

CSS output looks like:

:root {
  --tk-colors-primary: #4A90E2;
  --tk-colors-secondary: #50E3C2;
  --tk-colors-background: #FFFFFF;
  --tk-colors-text: #333333;
  --tk-typography-fontFamily: Inter, sans-serif;
  --tk-spacing-sm: 4px;
  --tk-spacing-md: 8px;
  --tk-spacing-lg: 16px;
}

Configuration

Drop a themekit.config.js in your project root:

module.exports = {
  tokens: './tokens.json',
  defaultTheme: 'light',
  aliasing: {
    enabled: true,
    maxDepth: 10,
  },
  persistence: {
    enabled: true,
    key: 'themekit-theme',
    storage: 'localStorage',
  },
  validation: {
    enabled: true,
    strict: false,
    rules: [
      {
        name: 'naming-convention',
        pattern: /^[a-z][a-zA-Z0-9-_]*$/,
        message: 'Use camelCase or kebab-case for token names',
        severity: 'warning',
      },
      {
        name: 'color-format',
        pattern: /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$|^rgb\(|^rgba\(/,
        message: 'Colors should be hex, rgb, or rgba',
        severity: 'error',
      },
    ],
  },
};

API

ThemeKit

const theme = new ThemeKit(config);

theme.registerTheme({ name: 'dark', tokens: {...} });
theme.switch('dark');
theme.getCurrentTheme();      // 'dark'
theme.getCurrentTokens();     // { colors: {...}, ... }
theme.getToken('colors.primary');
theme.getAvailableThemes();   // ['light', 'dark']
theme.prefetchThemes();       // Warm up caches for one or more themes
theme.addThemeChangeListener((name, tokens) => { ... });
theme.validateTokens(tokens); // { valid: true, errors: [] }

React Hooks

  • useTheme() — full theme context
  • useToken(path) — grab a specific token
  • useColor(name) — shorthand for colors
  • useTypography(name) — typography tokens
  • useSpacing(name) — spacing tokens

Vue Composables

Same deal: useThemeKit(), useToken(), useColor(), useTypography(), useSpacing()

Angular

Inject ThemeKitService and call switchTheme(), getToken(), etc.

Project Structure

src/
├── core/      # The main ThemeKit class
├── types/     # TypeScript definitions
├── react/     # React bindings
├── vue/       # Vue bindings
├── angular/   # Angular bindings
├── vanilla/   # Vanilla JS adapter
└── cli/       # CLI commands

Tips

  • Keep tokens atomic (e.g., blue-500) rather than semantic (e.g., button-background)
  • Version control your token files
  • Run validation in CI so bad tokens don't slip through
  • Generate static CSS for production when you can

What's Next

  • Svelte and SolidJS adapters
  • Figma/Sketch sync
  • Multi-brand support
  • Visual token editor

Contributing

git clone https://github.com/M1tsumi/Theme-Kit.git
cd Theme-Kit
npm install
npm run dev

Run tests with npm test, build with npm run build.

License

MIT