eddev
Design System

Colours

Configure colour tokens and Figma handoff output for Tailwind.

Current eddev themes still use Tailwind v3, so design tokens are wired through tailwind.config.ts. The starter theme currently includes tailwind-helper/, and real sites copy or adjust that helper in the theme rather than relying on a shared package.

The Figma handoff plugin can produce ED. Tailwind snippets for colours, typography, spacing, size, and radius tokens. Treat that output as a starting point, then keep the final contract in tailwind.config.ts.

Configuration

Import responsiveTheme from the local helper and pass colour tokens into the plugin config.

import ContainerQueries from "@tailwindcss/container-queries"
import { Config } from "tailwindcss"
import { responsiveTheme } from "./tailwind-helper/plugin"

export default {
  content: [
    "./views/**/*.{ts,tsx}",
    "./blocks/**/*.{ts,tsx}",
    "./components/**/*.{ts,tsx}",
    "./backend/**/*.{ts,tsx}",
    "./features/**/*.{ts,tsx}",
    "./utils/**/*.{ts,tsx}",
  ],
  plugins: [
    responsiveTheme({
      screens: { sm: 600, md: 900, lg: 1200, xl: 1600, xxl: 2000 },
      breakpoints: ["lg"],
      interpolate: {
        sm: {},
        md: { base: "sm", lerp: true },
        lg: { base: "lg", lerp: true },
        xl: { base: "lg", lerp: true },
        xxl: { base: "lg" },
      },
      colors: {
        base: {
          black: "#212121",
          white: "#ffffff",
          grey: {
            DEFAULT: "#757575",
            light: "#ecebea",
            dark: "#585858",
          },
          glass: "#f9f9f9",
        },
        semantic: {
          bg: "glass",
          fg: "black",
          muted: "grey",
        },
        subthemes: {
          "theme-dark": {
            bg: "black",
            fg: "glass",
            muted: "grey",
          },
        },
      },
    }),
    ContainerQueries,
  ],
} satisfies Config

base colours become normal Tailwind colour names such as text-black, bg-grey-light, and border-grey-dark. Nested DEFAULT values are exposed as the parent name.

The helper stores colours as CSS variables using Tailwind's alpha-aware colour format, so opacity modifiers keep working:

<div className="bg-grey-light text-black">
  <p className="text-black/60">Secondary text</p>
</div>

Use solid hex or rgb(...) values for generated colour tokens.

Figma Export

Open Plugins -> From ED. -> ED. Web Handoff in Figma and use the Colours panel. The plugin reads local paint styles and colour variables, reports naming or unsupported-fill issues, and shows an ED. Tailwind code block.

Naming rules to keep exports clean:

Figma SourceTailwind Token
Blackblack
Grey/Lightgrey.light in config, bg-grey-light in classes
Grey/Defaultgrey.DEFAULT in config, bg-grey in classes
Theme variable Backgroundbg semantic token

Paint styles or variables whose name starts with _, or contains /_, are ignored by the extractor. Use that for design-only swatches that should not ship as code tokens.

Semantic Colours

Semantic colours are the theme-ready layer. Use them when a component or section should adapt to a subtheme or colour scheme rather than lock itself to specific named colours.

export function Panel(props: { children: React.ReactNode }) {
  return (
    <section className="theme-dark bg-bg text-fg p-5 rounded-md">
      {props.children}
    </section>
  )
}

The semantic map defines the default CSS variables:

colors: {
  semantic: {
    bg: "glass",
    fg: "black",
    "fg-secondary": "grey",
  },
}

The helper adds --color-bg, --color-fg, and matching Tailwind colours. A subtheme class overrides the same variables inside that subtree.

Subthemes

Subthemes are Tailwind classes that remap semantic colour variables inside a subtree. They let the same component keep using classes such as bg-bg, text-fg, and text-fg-secondary while the wrapper decides which base colours those classes resolve to.

Subtheme keys are literal class names. If the key is "theme-dark", the class is .theme-dark and the generated ancestor variant is is-theme-dark:.

colors: {
  subthemes: {
    "theme-light": {
      bg: "white",
      fg: "black",
      "fg-secondary": "grey",
    },
    "theme-dark": {
      bg: "black",
      fg: "white",
      "fg-secondary": "grey.light",
    },
  },
}
<section className="theme-dark bg-bg text-fg">
  <h2 className="type-title-l">Dark section</h2>
  <a className="text-fg-secondary hover:text-fg">Read more</a>
</section>

Use the generated is-* variants when a child needs to react to an ancestor theme:

<article className="bg-orange text-fg is-theme-dark:theme-light is-theme-dark:bg-white">
  ...
</article>

For author-selectable schemes and TypeScript mapping helpers, see Colour Schemes.

On this page