Literal font family names

In @theme inline, name fonts literally, not by runtime variable.

From shadcn (Vercel plugin): Component Gotchas, Geist font in Next.js.

Three font declarations

Switch the --font-sans line; two of three fall back.

--font-sans declaration
globals.cssSource
RenderedBad
<html>
<body class="geist.variable antialiased">

Revenue up 18% this quarter

Net margin held at 22% on flat headcount.

Where the variable class lives

Move the class chip between <html> and <body>.

Variable classes on
--font-sans in @theme inline
Bad
<html class="">
<body class=" antialiased">
  • <h1>Revenue up 18%
  • <p>Plain paragraph text
  • .font-sansApprove bill
  • .font-monoINV-2041
/* globals.css */
@theme inline {
  --font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif;
  --font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, monospace;
}

// app/layout.tsx
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
  <body className="antialiased">{children}</body>
</html>

Why it matters, pros and cons

Why it matters

@theme inline bakes values in at build; runtime variables resolve to nothing.

Pros

  • Resolves wherever the classes land.
  • Devtools shows the real font stack.
  • Survives shadcn init rewrites.

Cons

  • The family name now lives in two places.
  • A custom localFont fallback name may differ.
  • Plain @theme with classes on <html> also works.