How to make a shadcn/ui theme from any website

Updated 3 November 2026. Every command and output on this page is real.

To make a shadcn/ui theme from a website, run npx designlang <url> --framework shadcn; it maps the site’s extracted background, foreground, primary, secondary, accent, muted and border colours and its radius onto shadcn’s CSS variables, ready to paste into globals.css.

Steps

  1. Extract the site with the shadcn emitter. Run npx designlang stripe.com --framework shadcn.
  2. Open the theme file. Open design-extract-output/stripe-com-shadcn-theme.css. It holds a :root block of shadcn variables.
  3. Paste it into globals.css. Replace the :root variables in your shadcn globals.css with the generated ones.
  4. Check contrast and dark mode. Check the foreground pairs for WCAG contrast and rerun with --dark if the site has a dark theme.

shadcn/ui is the default component kit for a lot of AI-generated UI. v0, Cursor and Claude all reach for it, which is why so many new apps share the same neutral look. The components are fine. The theme is the part that makes them yours, and a shadcn theme is just a handful of CSS variables.

designlang fills those variables from a real site. It reads the brand colours, the page surface, body text, muted surfaces, borders and the common corner radius, and writes them in shadcn’s format.

Generate it

npx designlang stripe.com --framework shadcn

This is the complete theme file it wrote for stripe.com. Captured with designlang 13.3.2 on 3 November 2026.

/* shadcn/ui Theme — extracted from https://stripe.com */
/* Paste into your globals.css */

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 211 78% 11%;
    --primary: 248 98% 61%;
    --primary-foreground: 0 0% 100%;
    --secondary: 211 78% 11%;
    --secondary-foreground: 0 0% 100%;
    --accent: 151 100% 42%;
    --accent-foreground: 0 0% 100%;
    --muted: 215 86% 97%;
    --muted-foreground: 0 0% 0%;
    --border: 218 18% 57%;
    --radius: 8px;
  }
}

Each value is an HSL channel triplet: 248 98% 61% is #533afd, Stripe’s purple, and 211 78% 11% is the deep navy #061b31 used for body text.

Apply it

Open the globals.css that shadcn created and replace the variables inside :root with the generated ones. Every component that reads --primary, --border or --radius now uses the new values. Buttons, inputs, cards, dialogs and badges all change at once, because shadcn components never hardcode colours.

If your project uses Tailwind v4

Newer shadcn projects on Tailwind v4 store full colour values (often oklch(...)) instead of bare channels, and read them with var(--primary). Wrap each generated triplet in hsl() when you paste it:

:root {
  --primary: hsl(248 98% 61%);
  --primary-foreground: hsl(0 0% 100%);
  --radius: 8px;
}

How the colours are chosen

shadcn variableExtracted from
--backgroundThe largest page surface.
--foregroundThe body text colour.
--primaryThe brand primary: the colour of main buttons and links.
--secondaryThe second brand colour.
--accentThe highlight colour, if the site has one (#00d66f on stripe.com).
--mutedA raised or tinted surface.
--borderThe most common border colour.
--radiusThe common control radius.

Things to check

  • Foreground pairs. The emitter picks a readable foreground for each colour, but always check. The --accent-foreground above is white on a bright green, which is low contrast; the tokens file pairs the same accent with navy (onAccent: #061b31), which reads better. Swap it if you use the accent for text.
  • Variables the emitter does not write, such as --card, --popover, --ring, --input, --destructive and the chart colours, keep their shadcn defaults. Set --ring to the primary and --input to the border for a closer match.
  • Dark mode. Rerun with --dark to read the site’s dark theme, then put those values in your .dark block.
  • Fonts. shadcn does not set a font. Use the family from stripe-com-DESIGN.md or the Tailwind file.

Going further than colours

A shadcn theme covers colour and radius. A brand also has a type scale, spacing rhythm, shadows and motion. For those, use the Tailwind output from the same run (see converting a website to a Tailwind theme) and the motion presets in stripe-com-motion.css.

Other frameworks get the same treatment: --framework react, --framework vue and --framework svelte write theme objects for those stacks.

A button before and after

Nothing in the component changes. This is the stock shadcn button markup, which reads the variables through Tailwind classes:

<Button>Start trial</Button>
// renders roughly as:
<button class="bg-primary text-primary-foreground rounded-md h-10 px-4 ...">Start trial</button>

With the default theme, bg-primary is near-black. With the stripe.com theme it is #533afd, text-primary-foreground is white (6.19:1 contrast, which passes AA), and rounded-md follows the 8px --radius. Every variant (secondary, outline, ghost) shifts the same way, because they all read the same variables.

Choosing the source site

  • For your own product, point it at your production marketing site or app. That is where the brand is most complete.
  • For a new product with no site yet, read a few sites whose feel you want and compare them with npx designlang brands a.com b.com c.com before picking one to start from.
  • If the result picks the wrong primary, pass --palette 8 to merge near-duplicates, or edit the one variable by hand. It is a CSS file.

Keep AI-written components on the theme

AI editors often bypass the variables and write bg-[#3b82f6] straight into a component. Run npx designlang check src on the result to catch it, and give the editor your tokens through MCP so it uses bg-primary in the first place. The MCP guide shows the setup.

Questions

Does it change my components?
No. It writes CSS variables only. Your components stay as they are and pick up the new values.
Can I make a shadcn theme from a site that is not mine?
Yes, for study and prototypes. Ship your own brand in production.

Try it on any site

One command, no account: npx designlang stripe.com.