# Match theme-color to the Page Background

**SHOULD** · **ID:** `design-theme-color-meta` · **Category:** design
**Source:** [Vercel](https://github.com/vercel-labs/agent-skills/blob/main/skills/web-design-guidelines/SKILL.md)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/design-theme-color-meta

> SHOULD: Match the mobile browser and PWA chrome to the page background by shipping one `<meta name="theme-color">` per scheme with the literal background value — a `<meta>` tag cannot read CSS custom properties, and leaving it unset puts a default light address bar above a dark page.

Declare a <meta name="theme-color"> per color scheme so browser chrome matches the page

On mobile, the surface directly above your page is not yours — Safari and Chrome tint the address bar, and an installed PWA tints its title bar and task-switcher card, from `<meta name="theme-color">`. Leave it unset and that chrome keeps a default light fill, producing a hard seam above a dark page. A `<meta>` tag cannot read CSS custom properties, so ship one tag per scheme with the literal background value and a `media` attribute: `media="(prefers-color-scheme: dark)"` and a matching light one.

## Rule snippet

```tsx
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#0a0a0a" media="(prefers-color-scheme: dark)">
```

## Bad — do not do this

`design-theme-color-meta-bad`

```tsx
/**
 * BAD: No <meta name="theme-color">. The page ships a dark surface, but mobile
 * browser chrome (Safari/Chrome address bar, the PWA title bar, the Android task
 * switcher card) keeps its default light fill — so the app ends up wearing a
 * bright collar it never asked for.
 */
export function ThemeColorMetaBad() {
  return (
    <div className="w-full max-w-md space-y-4">
      <div className="bg-muted rounded-md p-3 font-mono text-xs overflow-x-auto">
        <pre className="text-error">{`<head>
  <title>Dashboard</title>
  <!-- no theme-color: browser chrome -->
  <!-- keeps its own default fill     -->
</head>`}</pre>
      </div>

      {/* Phone mockup */}
      <div className="mx-auto w-56 rounded-3xl border-4 border-border bg-border p-1">
        <div className="overflow-hidden rounded-[1.25rem]">
          {/* Browser chrome — NOT in the dark scope: default light fill */}
          <div className="bg-background text-foreground px-3 py-1.5">
            <div className="flex items-center justify-between text-[9px] font-medium">
              <span>9:41</span>
              <span>••••</span>
            </div>
            <div className="mt-1 rounded-full bg-muted px-2 py-0.5 text-[9px] text-muted-foreground">
              acme.app
            </div>
          </div>

          {/* The actual page: dark */}
          <div className="dark bg-background text-foreground px-3 py-4 space-y-2">
            <div className="text-[10px] font-semibold">Dashboard</div>
            <div className="h-2 w-4/5 rounded bg-muted" />
            <div className="h-2 w-3/5 rounded bg-muted" />
            <div className="h-6 w-24 rounded bg-primary" />
          </div>
        </div>
      </div>

      <p className="text-xs text-error">
        A hard seam: the browser chrome bar stays light while the page below it is
        dark. On iOS and Android this is the first thing the user sees.
      </p>
    </div>
  );
}
```

## Good — do this

`design-theme-color-meta-good`

```tsx
/**
 * GOOD: <meta name="theme-color"> is declared once per color scheme, each value
 * equal to that scheme's page background. Mobile browser chrome and the PWA title
 * bar adopt the page surface, so the app extends edge-to-edge with no visible seam.
 */
export function ThemeColorMetaGood() {
  return (
    <div className="w-full max-w-md space-y-4">
      <div className="bg-muted rounded-md p-3 font-mono text-xs overflow-x-auto">
        <pre className="text-foreground">{`<head>
  <title>Dashboard</title>
  <meta name="theme-color"
    media="(prefers-color-scheme: light)"
    content="oklch(0.98 0.0025 106)" />
  <meta name="theme-color"
    media="(prefers-color-scheme: dark)"
    content="oklch(0.147 0.004 49.25)" />
</head>`}</pre>
      </div>

      {/* Phone mockup */}
      <div className="mx-auto w-56 rounded-3xl border-4 border-border bg-border p-1">
        {/* Chrome AND page share one dark scope: one continuous surface */}
        <div className="dark overflow-hidden rounded-[1.25rem] bg-background text-foreground">
          {/* Browser chrome — now painted with the page background */}
          <div className="px-3 py-1.5">
            <div className="flex items-center justify-between text-[9px] font-medium">
              <span>9:41</span>
              <span>••••</span>
            </div>
            <div className="mt-1 rounded-full bg-muted px-2 py-0.5 text-[9px] text-muted-foreground">
              acme.app
            </div>
          </div>

          {/* The actual page */}
          <div className="px-3 py-4 space-y-2">
            <div className="text-[10px] font-semibold">Dashboard</div>
            <div className="h-2 w-4/5 rounded bg-muted" />
            <div className="h-2 w-3/5 rounded bg-muted" />
            <div className="h-6 w-24 rounded bg-primary" />
          </div>
        </div>
      </div>

      <p className="text-xs text-success">
        Chrome bar and page share one surface — the seam is gone and the app reads as
        edge-to-edge.
      </p>
    </div>
  );
}
```

## References

- [MDN: meta name="theme-color"](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/meta/name/theme-color)
