Skip to content

Add fontsource and support override for registry:font install#9929

Merged
shadcn merged 19 commits intoshadcn-ui:mainfrom
kapishdima:fix/registry-font
Mar 14, 2026
Merged

Add fontsource and support override for registry:font install#9929
shadcn merged 19 commits intoshadcn-ui:mainfrom
kapishdima:fix/registry-font

Conversation

@kapishdima
Copy link
Copy Markdown
Contributor

When shadcn add installs a registry:font in a non-Next.js project (Vite, React Router, Astro, etc.), it always uses @fontsource-variable/{fontName}
This causes two problems:

  1. Not all fonts have a @fontsource-variable/ package. For example, Lato isn’t available in fontsource/variable - it’s available in fontsource
  2. @fontsource-variable/ packages register fonts with a "Variable" suffix (e.g., "Inter Variable" instead of "Inter"), which may not match what users expect

Goal: Install both @fontsource/{fontName} (base) and @fontsource-variable/{fontName} (variable), using CSS @supports so that variable fonts are loaded only in clients that support them.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 9, 2026

@kapishdima is attempting to deploy a commit to the shadcn-pro Team on Vercel.

A member of the Team first needs to authorize it.

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn , I also have this issue in Fonttrio

image

I’m thinking - what if I make the installation use only fontsource (non-variable fonts)? That should be more stable

Of course, I could add a check for whether the font exists in fontsource/variable, but it feels like that would increase the cognitive load in the code 🙃

@shadcn
Copy link
Copy Markdown
Collaborator

shadcn commented Mar 9, 2026

Let me take a look. I'll come up with a solution.

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn just ping :DD

const fontName = fontSans.name.replace("font-", "")
const fontSourceDependency = `@fontsource-variable/${fontName}`
const fontSourceBase = `@fontsource/${fontName}`
const fontSourceVariable = `@fontsource-variable/${fontName}`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a font does not have a variable variant, this will still fail right? eg. @fontsource-variable/lato will fail.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I realized that after I created the PR, which is why I suggested installing only fontsource without variable. Alternatively, we could send a request and check whether the font exists in fontsource/variable

@shadcn
Copy link
Copy Markdown
Collaborator

shadcn commented Mar 10, 2026

I'm checking if the following would be better: a dependency field.

{
  "name": "font-inter",
  "type": "registry:font",
  "font": {
    "family": "'Inter Variable', sans-serif",
    "provider": "google",
    "import": "Inter",
    "variable": "--font-sans",
    "dependency": "@fontsource-variable/inter" // ←
  }
}
{
  "name": "font-lato",
  "type": "registry:font",
  "font": {
    "family": "'Lato', sans-serif",
    "provider": "google",
    "import": "Lato",
    "variable": "--font-sans",
    "weight": ["400", "700"],
    "dependency": "@fontsource/lato" // ←
  }
}

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn Hmm, but what if the user has only fontsource/variable specified in dependency, and the font is installed only from there — but the browser doesn’t support variable fonts? Then a fallback would have to be added manually.

My PR does a few things:

  • Installs both fontsource and fontsource/variable
  • Adds a @supports block in CSS so both variants are supported
  • Fixes the issue in non-Next.js projects where the font-family is used without the Variable suffix, while fontsource/variable imports it with the suffix.

For example, fontsource/variable exports "Fira Code Variable", but the CSS currently uses just "Fira Code".

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn , I thought a lot about something like this. Then registry authors wouldn’t need to worry about whether a font is supported in fontsource:

// ...
const response = await fetch(`https://registry.npmjs.org/@fontsource-variable/{fontName}`);

if(response.ok) {
	tree.css[`@import "${fontSourceVariable}"`] = {}
}
// ...

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn , ping :D

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn, Do you have any solution? Or should I implement a check using a request? Because right now users cannot properly set the font in the TanStack Start application

@shadcn
Copy link
Copy Markdown
Collaborator

shadcn commented Mar 14, 2026

@kapishdima I wouldn't worry about fallback. Usage is at 97%. https://caniuse.com/variable-fonts

shadcn and others added 3 commits March 14, 2026 15:33
…ontrol.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@shadcn
Copy link
Copy Markdown
Collaborator

shadcn commented Mar 14, 2026

wdyt #10035?

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn , Let’s do it this way then, I’ll pass it on to Fonttrio from my side. Thanks!

@shadcn
Copy link
Copy Markdown
Collaborator

shadcn commented Mar 14, 2026

@kapishdima Ready to test with npx shadcn@4.0.7-beta.1 let me know.

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ui Ignored Ignored Preview Mar 14, 2026 0:26am

Request Review

@shadcn
Copy link
Copy Markdown
Collaborator

shadcn commented Mar 14, 2026

@kapishdima ready when you are.

@kapishdima
Copy link
Copy Markdown
Contributor Author

I’ll go test it

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn , I tested installing a font that doesn’t exist in fontsource/variable - it works fine.

There’s another thing though. I have a registry item like this

{
	"name": "fira-code",
	"type": "registry:font",
	"category": "Monospace",
	"title": "Fira Code",
	"description": "Fira Code — Monospace font.",
	"font": {
		"family": "Fira Code",
		"provider": "google",
		"import": "Fira_Code",
		"variable": "--font-fira-code",
		"weight": ["300", "400", "500", "600", "700"],
		"subsets": [
			"menu",
			"cyrillic",
			"cyrillic-ext",
			"greek",
			"greek-ext",
			"latin",
			"latin-ext",
			"symbols2"
		]
	}
}

where font.family is Fira Code. When installing the font, you use font.family to add a CSS variable like:

--font-fira-code: Fira Code

But the font-family in fontsource/variable is actually "Fira Code Variable".

@font-face {
  font-family: 'Fira Code Variable';
  font-style: normal;
  font-display: swap;
  font-weight: 300 700;
  src: url(./files/fira-code-cyrillic-ext-wght-normal.woff2) format('woff2-variations');
  unicode-range: U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F;
}

I can solve this at the registry-item level by simply setting font.family to Fira Code Variable. But other users might not know about this.

What do you think? Is it better to let users specify the correct font-family themselves, or should this be handled in the CLI?

@shadcn
Copy link
Copy Markdown
Collaborator

shadcn commented Mar 14, 2026

Yes. That's right. The dependency field gives you explicit control here. Set family to match whatever package you're using:

  • "family": "'Fira Code Variable', monospace" with "dependency": "@fontsource-variable/fira-code"
  • "family": "'Fira Code', monospace" with "dependency": "@fontsource/fira-code"

It should be deterministic. The CLI shouldn't transform or guess font names. We leave that to the registry author.

@kapishdima
Copy link
Copy Markdown
Contributor Author

@shadcn Alright, everything works then. Thank you so much!

@shadcn shadcn merged commit a0a072d into shadcn-ui:main Mar 14, 2026
1 check failed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants