Skip to content

abernier/react-mcu

 
 

Repository files navigation

npm version

Material Design colors for React.

It injects --mcu-* CSS variables into the page.

react-mcu.mp4

m3 references:

builder roles
CleanShot 2026-01-14 at 08 58 40@2x CleanShot 2026-01-14 at 09 01 23@2x

Usage

import { Mcu } from "react-mcu";

<Mcu
  source="#0e1216"
  scheme="vibrant"
  contrast={0.5}
  customColors={[
    { name: "myCustomColor1", hex: "#6C8A0C", blend: true },
    { name: "myCustomColor2", hex: "#E126C6", blend: true },
    { name: "myCustomColor3", hex: "#E126C6", blend: false },
  ]}
>
  <p style={{
    backgroundColor: "var(--mcu-surface)",
    color: "var(--mcu-on-surface)",
  }}>
    Hello, MCU <span style={{
      backgroundColor: "var(--mcu-my-custom-color-1)",
      color: "var(--mcu-on-my-custom-color-1)",
    }}>colors<span>!
  </p>
</Mcu>

Tip

Typically wrapping {children} in a layout.

Note

CSS varnames are always kebab-cased, myCustomColor1 → --mcu-my-custom-color-1

useMcu

A hook is also provided:

import { useMcu } from "react-mcu";

const { initials, setMcuConfig, getMcuColor } = useMcu();

return (
  <button onClick={() => setMcuConfig({ ...initials, source: "#FF5722" })}>
    Change to {getMcuColor("primary", "light")}
  </button>
);

Tailwind

Compatible through theme variables:

@theme inline {
--color-background: var(--mcu-background);
--color-on-background: var(--mcu-on-background);
--color-surface: var(--mcu-surface);
--color-surface-dim: var(--mcu-surface-dim);
--color-surface-bright: var(--mcu-surface-bright);
--color-surface-container-lowest: var(--mcu-surface-container-lowest);
--color-surface-container-low: var(--mcu-surface-container-low);
--color-surface-container: var(--mcu-surface-container);
--color-surface-container-high: var(--mcu-surface-container-high);
--color-surface-container-highest: var(--mcu-surface-container-highest);
--color-on-surface: var(--mcu-on-surface);
--color-on-surface-variant: var(--mcu-on-surface-variant);
--color-outline: var(--mcu-outline);
--color-outline-variant: var(--mcu-outline-variant);
--color-inverse-surface: var(--mcu-inverse-surface);
--color-inverse-on-surface: var(--mcu-inverse-on-surface);
--color-primary: var(--mcu-primary);
--color-on-primary: var(--mcu-on-primary);
--color-primary-container: var(--mcu-primary-container);
--color-on-primary-container: var(--mcu-on-primary-container);
--color-primary-fixed: var(--mcu-primary-fixed);
--color-primary-fixed-dim: var(--mcu-primary-fixed-dim);
--color-on-primary-fixed: var(--mcu-on-primary-fixed);
--color-on-primary-fixed-variant: var(--mcu-on-primary-fixed-variant);
--color-inverse-primary: var(--mcu-inverse-primary);
--color-secondary: var(--mcu-secondary);
--color-on-secondary: var(--mcu-on-secondary);
--color-secondary-container: var(--mcu-secondary-container);
--color-on-secondary-container: var(--mcu-on-secondary-container);
--color-secondary-fixed: var(--mcu-secondary-fixed);
--color-secondary-fixed-dim: var(--mcu-secondary-fixed-dim);
--color-on-secondary-fixed: var(--mcu-on-secondary-fixed);
--color-on-secondary-fixed-variant: var(--mcu-on-secondary-fixed-variant);
--color-tertiary: var(--mcu-tertiary);
--color-on-tertiary: var(--mcu-on-tertiary);
--color-tertiary-container: var(--mcu-tertiary-container);
--color-on-tertiary-container: var(--mcu-on-tertiary-container);
--color-tertiary-fixed: var(--mcu-tertiary-fixed);
--color-tertiary-fixed-dim: var(--mcu-tertiary-fixed-dim);
--color-on-tertiary-fixed: var(--mcu-on-tertiary-fixed);
--color-on-tertiary-fixed-variant: var(--mcu-on-tertiary-fixed-variant);
--color-error: var(--mcu-error);
--color-on-error: var(--mcu-on-error);
--color-error-container: var(--mcu-error-container);
--color-on-error-container: var(--mcu-on-error-container);
--color-scrim: var(--mcu-scrim);
--color-shadow: var(--mcu-shadow);
/* Shades */
--color-primary-50: var(--mcu-primary-95);
--color-primary-100: var(--mcu-primary-90);
--color-primary-200: var(--mcu-primary-80);
--color-primary-300: var(--mcu-primary-70);
--color-primary-400: var(--mcu-primary-60);
--color-primary-500: var(--mcu-primary-50);
--color-primary-600: var(--mcu-primary-40);
--color-primary-700: var(--mcu-primary-30);
--color-primary-800: var(--mcu-primary-20);
--color-primary-900: var(--mcu-primary-10);
--color-primary-950: var(--mcu-primary-5);
--color-secondary-50: var(--mcu-secondary-95);
--color-secondary-100: var(--mcu-secondary-90);
--color-secondary-200: var(--mcu-secondary-80);
--color-secondary-300: var(--mcu-secondary-70);
--color-secondary-400: var(--mcu-secondary-60);
--color-secondary-500: var(--mcu-secondary-50);
--color-secondary-600: var(--mcu-secondary-40);
--color-secondary-700: var(--mcu-secondary-30);
--color-secondary-800: var(--mcu-secondary-20);
--color-secondary-900: var(--mcu-secondary-10);
--color-secondary-950: var(--mcu-secondary-5);
--color-tertiary-50: var(--mcu-tertiary-95);
--color-tertiary-100: var(--mcu-tertiary-90);
--color-tertiary-200: var(--mcu-tertiary-80);
--color-tertiary-300: var(--mcu-tertiary-70);
--color-tertiary-400: var(--mcu-tertiary-60);
--color-tertiary-500: var(--mcu-tertiary-50);
--color-tertiary-600: var(--mcu-tertiary-40);
--color-tertiary-700: var(--mcu-tertiary-30);
--color-tertiary-800: var(--mcu-tertiary-20);
--color-tertiary-900: var(--mcu-tertiary-10);
--color-tertiary-950: var(--mcu-tertiary-5);
--color-error-50: var(--mcu-error-95);
--color-error-100: var(--mcu-error-90);
--color-error-200: var(--mcu-error-80);
--color-error-300: var(--mcu-error-70);
--color-error-400: var(--mcu-error-60);
--color-error-500: var(--mcu-error-50);
--color-error-600: var(--mcu-error-40);
--color-error-700: var(--mcu-error-30);
--color-error-800: var(--mcu-error-20);
--color-error-900: var(--mcu-error-10);
--color-error-950: var(--mcu-error-5);
--color-neutral-50: var(--mcu-neutral-95);
--color-neutral-100: var(--mcu-neutral-90);
--color-neutral-200: var(--mcu-neutral-80);
--color-neutral-300: var(--mcu-neutral-70);
--color-neutral-400: var(--mcu-neutral-60);
--color-neutral-500: var(--mcu-neutral-50);
--color-neutral-600: var(--mcu-neutral-40);
--color-neutral-700: var(--mcu-neutral-30);
--color-neutral-800: var(--mcu-neutral-20);
--color-neutral-900: var(--mcu-neutral-10);
--color-neutral-950: var(--mcu-neutral-5);
--color-neutral-variant-50: var(--mcu-neutral-variant-95);
--color-neutral-variant-100: var(--mcu-neutral-variant-90);
--color-neutral-variant-200: var(--mcu-neutral-variant-80);
--color-neutral-variant-300: var(--mcu-neutral-variant-70);
--color-neutral-variant-400: var(--mcu-neutral-variant-60);
--color-neutral-variant-500: var(--mcu-neutral-variant-50);
--color-neutral-variant-600: var(--mcu-neutral-variant-40);
--color-neutral-variant-700: var(--mcu-neutral-variant-30);
--color-neutral-variant-800: var(--mcu-neutral-variant-20);
--color-neutral-variant-900: var(--mcu-neutral-variant-10);
--color-neutral-variant-950: var(--mcu-neutral-variant-5);
/*
* Custom colors
*/
--color-myCustomColor1: var(--mcu-my-custom-color-1);
--color-on-myCustomColor1: var(--mcu-on-my-custom-color-1);
--color-myCustomColor1-container: var(--mcu-my-custom-color-1-container);
--color-on-myCustomColor1-container: var(
--mcu-on-my-custom-color-1-container
);
/* Shades */
--color-myCustomColor1-50: var(--mcu-my-custom-color-1-95);
--color-myCustomColor1-100: var(--mcu-my-custom-color-1-90);
--color-myCustomColor1-200: var(--mcu-my-custom-color-1-80);
--color-myCustomColor1-300: var(--mcu-my-custom-color-1-70);
--color-myCustomColor1-400: var(--mcu-my-custom-color-1-60);
--color-myCustomColor1-500: var(--mcu-my-custom-color-1-50);
--color-myCustomColor1-600: var(--mcu-my-custom-color-1-40);
--color-myCustomColor1-700: var(--mcu-my-custom-color-1-30);
--color-myCustomColor1-800: var(--mcu-my-custom-color-1-20);
--color-myCustomColor1-900: var(--mcu-my-custom-color-1-10);
--color-myCustomColor1-950: var(--mcu-my-custom-color-1-5);
--color-myCustomColor2: var(--mcu-my-custom-color-2);
--color-on-myCustomColor2: var(--mcu-on-my-custom-color-2);
--color-myCustomColor2-container: var(--mcu-my-custom-color-2-container);
--color-on-myCustomColor2-container: var(
--mcu-on-my-custom-color-2-container
);
/* Shades */
--color-myCustomColor2-50: var(--mcu-my-custom-color-2-95);
--color-myCustomColor2-100: var(--mcu-my-custom-color-2-90);
--color-myCustomColor2-200: var(--mcu-my-custom-color-2-80);
--color-myCustomColor2-300: var(--mcu-my-custom-color-2-70);
--color-myCustomColor2-400: var(--mcu-my-custom-color-2-60);
--color-myCustomColor2-500: var(--mcu-my-custom-color-2-50);
--color-myCustomColor2-600: var(--mcu-my-custom-color-2-40);
--color-myCustomColor2-700: var(--mcu-my-custom-color-2-30);
--color-myCustomColor2-800: var(--mcu-my-custom-color-2-20);
--color-myCustomColor2-900: var(--mcu-my-custom-color-2-10);
--color-myCustomColor2-950: var(--mcu-my-custom-color-2-5);
--color-myCustomColor3: var(--mcu-my-custom-color-3);
--color-on-myCustomColor3: var(--mcu-on-my-custom-color-3);
--color-myCustomColor3-container: var(--mcu-my-custom-color-3-container);
--color-on-myCustomColor3-container: var(
--mcu-on-my-custom-color-3-container
);
/* Shades */
--color-myCustomColor3-50: var(--mcu-my-custom-color-3-95);
--color-myCustomColor3-100: var(--mcu-my-custom-color-3-90);
--color-myCustomColor3-200: var(--mcu-my-custom-color-3-80);
--color-myCustomColor3-300: var(--mcu-my-custom-color-3-70);
--color-myCustomColor3-400: var(--mcu-my-custom-color-3-60);
--color-myCustomColor3-500: var(--mcu-my-custom-color-3-50);
--color-myCustomColor3-600: var(--mcu-my-custom-color-3-40);
--color-myCustomColor3-700: var(--mcu-my-custom-color-3-30);
--color-myCustomColor3-800: var(--mcu-my-custom-color-3-20);
--color-myCustomColor3-900: var(--mcu-my-custom-color-3-10);
--color-myCustomColor3-950: var(--mcu-my-custom-color-3-5);
}

Or simply:

@import "react-mcu/tailwind.css";

Important

Do not forget to manually add your custom colors, as in:

react-mcu/src/tailwind.css

Lines 126 to 185 in 688c789

/*
* Custom colors
*/
--color-myCustomColor1: var(--mcu-my-custom-color-1);
--color-on-myCustomColor1: var(--mcu-on-my-custom-color-1);
--color-myCustomColor1-container: var(--mcu-my-custom-color-1-container);
--color-on-myCustomColor1-container: var(
--mcu-on-my-custom-color-1-container
);
/* Shades */
--color-myCustomColor1-50: var(--mcu-my-custom-color-1-95);
--color-myCustomColor1-100: var(--mcu-my-custom-color-1-90);
--color-myCustomColor1-200: var(--mcu-my-custom-color-1-80);
--color-myCustomColor1-300: var(--mcu-my-custom-color-1-70);
--color-myCustomColor1-400: var(--mcu-my-custom-color-1-60);
--color-myCustomColor1-500: var(--mcu-my-custom-color-1-50);
--color-myCustomColor1-600: var(--mcu-my-custom-color-1-40);
--color-myCustomColor1-700: var(--mcu-my-custom-color-1-30);
--color-myCustomColor1-800: var(--mcu-my-custom-color-1-20);
--color-myCustomColor1-900: var(--mcu-my-custom-color-1-10);
--color-myCustomColor1-950: var(--mcu-my-custom-color-1-5);
--color-myCustomColor2: var(--mcu-my-custom-color-2);
--color-on-myCustomColor2: var(--mcu-on-my-custom-color-2);
--color-myCustomColor2-container: var(--mcu-my-custom-color-2-container);
--color-on-myCustomColor2-container: var(
--mcu-on-my-custom-color-2-container
);
/* Shades */
--color-myCustomColor2-50: var(--mcu-my-custom-color-2-95);
--color-myCustomColor2-100: var(--mcu-my-custom-color-2-90);
--color-myCustomColor2-200: var(--mcu-my-custom-color-2-80);
--color-myCustomColor2-300: var(--mcu-my-custom-color-2-70);
--color-myCustomColor2-400: var(--mcu-my-custom-color-2-60);
--color-myCustomColor2-500: var(--mcu-my-custom-color-2-50);
--color-myCustomColor2-600: var(--mcu-my-custom-color-2-40);
--color-myCustomColor2-700: var(--mcu-my-custom-color-2-30);
--color-myCustomColor2-800: var(--mcu-my-custom-color-2-20);
--color-myCustomColor2-900: var(--mcu-my-custom-color-2-10);
--color-myCustomColor2-950: var(--mcu-my-custom-color-2-5);
--color-myCustomColor3: var(--mcu-my-custom-color-3);
--color-on-myCustomColor3: var(--mcu-on-my-custom-color-3);
--color-myCustomColor3-container: var(--mcu-my-custom-color-3-container);
--color-on-myCustomColor3-container: var(
--mcu-on-my-custom-color-3-container
);
/* Shades */
--color-myCustomColor3-50: var(--mcu-my-custom-color-3-95);
--color-myCustomColor3-100: var(--mcu-my-custom-color-3-90);
--color-myCustomColor3-200: var(--mcu-my-custom-color-3-80);
--color-myCustomColor3-300: var(--mcu-my-custom-color-3-70);
--color-myCustomColor3-400: var(--mcu-my-custom-color-3-60);
--color-myCustomColor3-500: var(--mcu-my-custom-color-3-50);
--color-myCustomColor3-600: var(--mcu-my-custom-color-3-40);
--color-myCustomColor3-700: var(--mcu-my-custom-color-3-30);
--color-myCustomColor3-800: var(--mcu-my-custom-color-3-20);
--color-myCustomColor3-900: var(--mcu-my-custom-color-3-10);
--color-myCustomColor3-950: var(--mcu-my-custom-color-3-5);

shadcn

Pre-requisites:

Simply override/remap shadcn's CSS variables:

:root {
  /* ... */
}
.dark {
  /* ... */
}

:root,
.dark {
  --background: var(--mcu-surface);
  --foreground: var(--mcu-on-surface);
  --card: var(--mcu-surface-container-low);
  --card-foreground: var(--mcu-on-surface);
  --popover: var(--mcu-surface-container-high);
  --popover-foreground: var(--mcu-on-surface);
  --primary: var(--mcu-primary);
  --primary-foreground: var(--mcu-on-primary);
  --secondary: var(--mcu-secondary-container);
  --secondary-foreground: var(--mcu-on-secondary-container);
  --muted: var(--mcu-surface-container-highest);
  --muted-foreground: var(--mcu-on-surface-variant);
  --accent: var(--mcu-secondary-container);
  --accent-foreground: var(--mcu-on-secondary-container);
  --destructive: var(--mcu-error);
  --border: var(--mcu-outline-variant);
  --input: var(--mcu-outline);
  --ring: var(--mcu-primary);
  --chart-1: var(--mcu-primary-fixed);
  --chart-2: var(--mcu-secondary-fixed);
  --chart-3: var(--mcu-tertiary-fixed);
  --chart-4: var(--mcu-primary-fixed-dim);
  --chart-5: var(--mcu-secondary-fixed-dim);
  --sidebar: var(--mcu-surface-container-low);
  --sidebar-foreground: var(--mcu-on-surface);
  --sidebar-primary: var(--mcu-primary);
  --sidebar-primary-foreground: var(--mcu-on-primary);
  --sidebar-accent: var(--mcu-secondary-container);
  --sidebar-accent-foreground: var(--mcu-on-secondary-container);
  --sidebar-border: var(--mcu-outline-variant);
  --sidebar-ring: var(--mcu-primary);
}
mapping details see:
- https://chatgpt.com/share/6899f20a-422c-8011-a072-62fb649589a0
- https://gemini.google.com/share/51e072b6f1d2

Important

Make sure :root, .dark { ... } comes AFTER .root { ... } .dark { ... } to take precedence.

Dev

INSTALL

Pre-requisites:

  • Install nvm, then:
    $ nvm install
    $ nvm use
    $ node -v # make sure your version satisfies package.json#engines.node
    nb: if you want this node version to be your default nvm's one: nvm alias default node
  • Install pnpm, with:
    $ corepack enable
    $ corepack prepare --activate # it reads "packageManager"
    $ pnpm -v # make sure your version satisfies package.json#engines.pnpm
$ pnpm i

CONTRIBUTING

When submitting a pull request, please include a changeset to document your changes:

pnpm exec changeset

This helps us maintain the changelog and version the package appropriately.

Packages

No packages published

Languages

  • TypeScript 88.0%
  • CSS 11.6%
  • Other 0.4%