UI Library Integration

Scope: UI library integration using Variable Design Standard (VDS) outputs.

Failure if ignored: components bypass generated outputs and drift from the contract.

React integration

CSS variables

Use CSS variables in React:

function Button({ children }) {
  return <button className="button">{children}</button>;
}
                    
.button {
  background-color: var(--color-surface-brand);
  color: var(--color-text-primary);
}
                    

Inline styles with TypeScript

Use generated TypeScript types:

import { color, spacing } from "./tokens";
function Button({ children }: { children: React.ReactNode }) {
  return (
    <button
      style={{
        backgroundColor: color.surface.brand,
        color: color.text.primary,
        padding: spacing.component.button.padding,
      }}
    >
      {children}
    </button>
  );
}
                    

CSS-in-JS

Use with styled-components:

import styled from "styled-components";
import { color, spacing } from "./tokens";
const Button = styled.button`
  background-color: ${color.surface.brand};
  color: ${color.text.primary};
  padding: ${spacing.component.button.padding};
`;
                    

Use with emotion:

import { css } from "@emotion/react";
import { color, spacing } from "./tokens";
const buttonStyle = css`
  background-color: ${color.surface.brand};
  color: ${color.text.primary};
  padding: ${spacing.component.button.padding};
`;
function Button({ children }) {
  return <button css={buttonStyle}>{children}</button>;
}
                    

Theme context

Use theme context for mode switching:

import { createContext, useContext, useState } from "react";
import { color } from "./tokens";
const ThemeContext = createContext({
  theme: "light",
  setTheme: () => {},
  colors: color,
});
export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");
  const colors = {
    surface: color.surface[theme],
    text: color.text[theme],
  };
  return (
    <ThemeContext.Provider value={{ theme, setTheme, colors }}>
      {children}
    </ThemeContext.Provider>
  );
}
export function useTheme() {
  return useContext(ThemeContext);
}
                    

Vue integration

CSS variables

Use CSS variables in Vue:

<template>
  <button class="button">
    <slot></slot>
  </button>
</template>
<style scoped>
.button {
  background-color: var(--color-surface-brand);
  color: var(--color-text-primary);
}
</style>
                    

Style binding

Use style binding:

<template>
  <button :style="buttonStyle">
    <slot></slot>
  </button>
</template>
<script setup>
import { color, spacing } from "./tokens";
const buttonStyle = {
  backgroundColor: color.surface.brand,
  color: color.text.primary,
  padding: spacing.component.button.padding,
};
</script>
                    

Provide/inject

Use provide/inject for theme:

<script setup>
import { provide, inject, ref } from "vue";
import { color } from "./tokens";
const theme = ref("light");
provide("theme", theme);
provide("colors", {
  surface: color.surface[theme.value],
  text: color.text[theme.value],
});
</script>
                    

Angular integration

CSS variables

Use CSS variables in Angular:

@Component({
  selector: "app-button",
  template: '<button class="button"><ng-content></ng-content></button>',
  styles: [
    `
      .button {
        background-color: var(--color-surface-brand);
        color: var(--color-text-primary);
      }
    `,
  ],
})
export class ButtonComponent {}
                    

Style binding

Use style binding:

import { Component } from "@angular/core";
import { color, spacing } from "./tokens";
@Component({
  selector: "app-button",
  template: '<button [style]="buttonStyle"><ng-content></ng-content></button>',
})
export class ButtonComponent {
  buttonStyle = {
    "background-color": color.surface.brand,
    color: color.text.primary,
    padding: spacing.component.button.padding,
  };
}
                    

Examples

React button component

Complete React button:

import { useTheme } from "./ThemeContext";
function Button({ children, variant = "primary" }) {
  const { colors } = useTheme();
  const backgroundColor =
    variant === "primary" ? colors.surface.brand : colors.surface.secondary;
  return (
    <button
      style={{
        backgroundColor,
        color: colors.text.primary,
        padding: "12px 24px",
      }}
    >
      {children}
    </button>
  );
}
                    

Vue button component

Complete Vue button:

<template>
  <button :class="['button', `button--${variant}`]" :style="buttonStyle">
    <slot></slot>
  </button>
</template>
<script setup>
import { computed } from "vue";
import { inject } from "vue";
import { color, spacing } from "./tokens";
const props = defineProps({
  variant: {
    type: String,
    default: "primary",
  },
});
const theme = inject("theme", "light");
const colors = computed(() => ({
  surface: color.surface[theme],
  text: color.text[theme],
}));
const buttonStyle = computed(() => ({
  backgroundColor:
    props.variant === "primary"
      ? colors.value.surface.brand
      : colors.value.surface.secondary,
  color: colors.value.text.primary,
  padding: spacing.component.button.padding,
}));
</script>
                    

Implementation rules

  1. Use CSS variables when possible
  2. Use TypeScript types for type safety
  3. Create theme context/hooks for mode switching
  4. Document library integration
  5. Test library consumption

Failure modes

If library integration is wrong:

  • Hardcoded values
  • No type safety
  • Broken mode switching
  • Inconsistent styling

Out of scope

  • React or Vue specific features (see tool docs)
  • State management (separate concern)
  • Component architecture (separate concern)