Recipes

Use brand colors in a Tailwind config

Drop the brandRNA brand pack directly into your Tailwind config to theme an entire app from a single fetch.

A brandRNA brand pack already speaks the same language Tailwind does: discrete role-tagged colours and named font families. Drop the pack into your tailwind.config.ts and the entire app inherits the target's brand identity — bg-brand-primary, text-brand-text, font-brand, all generated from one HTTP fetch.

Two approaches

ApproachWhenTrade-off
Build-timeYour app is themed at deploy time.Fastest runtime; requires a redeploy to refresh.
Request-timeMulti-tenant or per-user theming.CSS variables set at SSR; classes still work.

Build-time integration

Fetch the pack as a build step

Add a prebuild script that writes the pack to a JSON file. Keep your key in BRANDRNA_API_KEY:

// scripts/sync-brand.ts
import fs from "node:fs/promises";

const KEY = process.env.BRANDRNA_API_KEY!;
const DOMAIN = process.env.TARGET_DOMAIN ?? "stripe.com";

const res = await fetch(
  `https://api.brandrna.com/api/v1/pack/${DOMAIN}`,
  { headers: { Authorization: `Bearer ${KEY}` } },
);
if (!res.ok) throw new Error(`brandRNA ${res.status}`);
const pack = await res.json();
await fs.writeFile("./brand.json", JSON.stringify(pack, null, 2));
console.log(`brand.json updated for ${pack.brand}`);

Add to package.json:

{
  "scripts": {
    "prebuild": "tsx scripts/sync-brand.ts"
  }
}

Wire the pack into Tailwind

// tailwind.config.ts
import type { Config } from "tailwindcss";
import pack from "./brand.json";

export default {
  content: ["./app/**/*.{ts,tsx}"],
  theme: {
    extend: {
      colors: {
        brand: {
          primary: pack.colors.primary,
          secondary: pack.colors.secondary,
          accent: pack.colors.accent,
          bg: pack.colors.background,
          text: pack.colors.text,
        },
      },
      fontFamily: {
        brand: [pack.fonts[0]?.family ?? "Inter", "sans-serif"],
      },
    },
  },
} satisfies Config;

Use the classes

export function Hero() {
  return (
    <section className="bg-brand-primary text-white font-brand py-24">
      <h1 className="text-5xl">Hello world</h1>
    </section>
  );
}

Every Tailwind utility — bg-brand-*, text-brand-*, border-brand-*, hover:bg-brand-accent — is now available.

Request-time (multi-tenant) integration

For SaaS apps where each tenant has their own theme, fetch at request time and inject CSS variables into the page head, then point Tailwind arbitrary values at those variables.

// app/layout.tsx (Next.js example)
async function fetchPack(domain: string) {
  const KEY = process.env.BRANDRNA_API_KEY!;
  const res = await fetch(
    `https://api.brandrna.com/api/v1/pack/${domain}`,
    { headers: { Authorization: `Bearer ${KEY}` }, next: { revalidate: 86400 } },
  );
  return res.json();
}

export default async function RootLayout({
  children,
  params,
}: { children: React.ReactNode; params: { tenant: string } }) {
  const pack = await fetchPack(params.tenant);
  const c = pack.colors;
  return (
    <html>
      <head>
        <style>{`
          :root {
            --brand-primary: ${c.primary};
            --brand-secondary: ${c.secondary};
            --brand-bg: ${c.background};
            --brand-text: ${c.text};
          }
        `}</style>
      </head>
      <body className="bg-[var(--brand-bg)] text-[var(--brand-text)]">
        {children}
      </body>
    </html>
  );
}

In your tailwind.config.ts, alias the variables so utility classes work:

extend: {
  colors: {
    "brand-primary": "var(--brand-primary)",
    "brand-secondary": "var(--brand-secondary)",
    "brand-bg": "var(--brand-bg)",
    "brand-text": "var(--brand-text)",
  },
}

Now bg-brand-primary resolves through the CSS variable at runtime — zero rebuild needed when the tenant changes.

OG image colour extraction

The brand pack includes a og_image_dominant colour where one was detectable. Use it for conditional dark/light treatments:

const isDark = (hex: string) => {
  const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));
  // perceived luminance
  return (0.299 * r + 0.587 * g + 0.114 * b) / 255 < 0.5;
};
const heroVariant = isDark(pack.colors.primary) ? "logo-light" : "logo-dark";

brandRNA already produces dark/light/transparent logo variants automatically — see pack.logos[i].variants. You don't need to generate them yourself.

What's next

On this page