Load custom fonts in Lovable by adding a Google Fonts link tag in index.html or placing local font files in /public/fonts/ with @font-face declarations. Then extend the fontFamily in tailwind.config.ts so you can use font-[name] classes. Conflicts with shadcn/ui defaults are resolved by overriding the sans key to set your font as the global default.
Why custom fonts conflict with default styles in Lovable projects
Lovable projects use Tailwind CSS with shadcn/ui, which sets a default font stack (typically Inter or the system sans-serif). When you add a custom font, three things can go wrong: the font loads but Tailwind does not know about it so no CSS class exists to apply it, the font's @font-face conflicts with existing declarations, or shadcn/ui component styles override your font setting with higher CSS specificity. Local fonts (files you upload to /public/fonts/) require an @font-face declaration that tells the browser the font family name, the file location, the weight, and the style. If any of these values are wrong, the browser silently falls back to the default font. The most common mistake is getting the src URL wrong — files in /public are served at the root, so /public/fonts/MyFont.woff2 becomes /fonts/MyFont.woff2 in the URL. Font conflicts with shadcn/ui happen because shadcn components inherit their font from the Tailwind theme. If you add a custom font to specific elements but do not update the Tailwind config, shadcn components continue using the default font, creating an inconsistent look throughout the app.
- Font loaded but not added to tailwind.config.ts — no CSS class exists to apply the font
- Wrong @font-face src path — /public/fonts/ files are served at /fonts/ not /public/fonts/
- CSS specificity conflict — shadcn/ui inherits from the Tailwind sans font, not your custom font
- Multiple @font-face declarations for the same family name with conflicting weights or styles
- Font file format not supported — some browsers need WOFF2, older ones need WOFF or TTF
Error messages you might see
Failed to decode downloaded font: /fonts/CustomFont.woff2The font file at this path is corrupted, the path is wrong (returning HTML instead of the font), or the file format is unsupported. Verify the file exists in /public/fonts/ and test the URL directly in the browser.
Font 'CustomFont' was not foundThe @font-face rule references a font family name that does not match any loaded font. Check the font-family value in your @font-face rule and make sure it matches exactly what you use in CSS.
The font 'CustomFont' does not have a valid src descriptorThe src path in your @font-face rule is incorrect. For files in /public/fonts/, use url('/fonts/CustomFont.woff2') with a leading slash.
Before you start
- A Lovable project open in the editor
- Your custom font files (WOFF2 format recommended) or the Google Fonts URL
- Access to Dev Mode to edit index.html and tailwind.config.ts
How to fix it
Add local font files to /public/fonts/
Vite serves files from /public at the root URL, making them available to @font-face rules
Add local font files to /public/fonts/
Vite serves files from /public at the root URL, making them available to @font-face rules
If you have font files (.woff2 is the best format for web), create a fonts folder inside /public. Upload your font files there using GitHub or Dev Mode. You need one file per weight and style combination — for example, Roboto-Regular.woff2, Roboto-Bold.woff2, and Roboto-Italic.woff2. WOFF2 has the best compression and is supported by all modern browsers.
Expected result: Font files are accessible at /fonts/FontName.woff2 when you visit the URL in the browser.
Declare the font with @font-face in index.html
The @font-face rule tells the browser the name, location, weight, and display strategy for each font file
Declare the font with @font-face in index.html
The @font-face rule tells the browser the name, location, weight, and display strategy for each font file
Open index.html in the project root. Add a style tag in the head section with @font-face declarations for each font file. Each declaration maps a specific weight and style to a file. Use font-display: swap to show fallback text immediately while the font loads.
<head> <meta charset="UTF-8" /> <title>My App</title></head><head> <meta charset="UTF-8" /> <title>My App</title> <style> @font-face { font-family: 'BrandFont'; src: url('/fonts/BrandFont-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; /* Show fallback text while font loads */ } @font-face { font-family: 'BrandFont'; src: url('/fonts/BrandFont-Bold.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; } </style></head>Expected result: The browser downloads the font files when the page loads. You can verify in the Network tab by filtering for 'font'.
Extend Tailwind configuration to include the custom font
Tailwind generates CSS classes based on the fontFamily config — without this, you cannot use font-brand in your components
Extend Tailwind configuration to include the custom font
Tailwind generates CSS classes based on the fontFamily config — without this, you cannot use font-brand in your components
Open tailwind.config.ts and add your font to the fontFamily section. If you want the font as the global default, override the sans key. If you want it available as an optional class, create a new key. Include fallback fonts in case the custom font fails to load.
export default { theme: { extend: {}, },};export default { theme: { extend: { fontFamily: { // Makes font-brand available as a class brand: ['BrandFont', 'Inter', 'sans-serif'], // Override sans to make BrandFont the global default sans: ['BrandFont', 'Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'], }, }, },};Expected result: The class font-brand applies your custom font. If you override sans, all text uses the custom font by default.
Resolve conflicts with shadcn/ui component fonts
shadcn/ui components inherit the Tailwind sans font — if you do not override sans, they use the default font instead of yours
Resolve conflicts with shadcn/ui component fonts
shadcn/ui components inherit the Tailwind sans font — if you do not override sans, they use the default font instead of yours
If you override the sans key in tailwind.config.ts, shadcn/ui components automatically use your custom font because they inherit from the Tailwind sans family. If you only added a custom key (like font-brand), shadcn/ui components still use the default font. To make everything consistent, either override sans globally or add the font-brand class to the body tag in index.html. If resolving font conflicts across many shadcn/ui components requires changes to the theme configuration, RapidDev's engineers have configured custom typography across 600+ Lovable projects.
<body> <div id="root"></div></body><body class="font-brand antialiased"> <div id="root"></div></body>Expected result: All text in the app, including shadcn/ui components, uses your custom font consistently.
Complete code example
1import type { Config } from "tailwindcss";23export default {4 darkMode: ["class"],5 content: ["./index.html", "./src/**/*.{ts,tsx}"],6 theme: {7 extend: {8 fontFamily: {9 // Custom brand font loaded via @font-face in index.html10 brand: ['BrandFont', 'Inter', 'sans-serif'],11 // Heading font from Google Fonts12 heading: ['Playfair Display', 'Georgia', 'serif'],13 // Override default sans-serif to use brand font globally14 sans: ['BrandFont', 'Inter', 'ui-sans-serif', 'system-ui', 'sans-serif'],15 },16 // Ensure custom font classes survive Tailwind's purge17 // by using them in templates (not dynamically)18 },19 },20 plugins: [require("tailwindcss-animate")],21} satisfies Config;Best practices to prevent this
- Use WOFF2 format for all custom fonts — it has the best compression and is supported by all modern browsers
- Always include font-display: swap in @font-face rules to prevent invisible text while the font loads
- Override the Tailwind sans key if you want your font as the global default — this ensures shadcn/ui components also use it
- Include fallback fonts in your fontFamily arrays so text remains readable if the custom font fails to load
- Place font files in /public/fonts/ and reference them with a leading slash in the URL: url('/fonts/file.woff2')
- Load only the weights you need — each weight adds 20-50KB to the page load time
- Add font-preload link tags in index.html for critical fonts to speed up initial rendering
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I have a Lovable.dev project and I want to add a custom font. My project uses Tailwind CSS + shadcn/ui. Font details: - Font name: [name] - Source: [Google Fonts URL or local files] - Weights needed: [400, 700, etc.] - Should this be the global default? [yes/no] Please help me: 1. Create the @font-face declarations (or Google Fonts link tag) 2. Update tailwind.config.ts with the font 3. Apply it globally or to specific elements 4. Resolve any conflicts with shadcn/ui default fonts
Add the custom font BrandFont to my project. I have uploaded BrandFont-Regular.woff2 and BrandFont-Bold.woff2 to /public/fonts/. Add @font-face declarations in @index.html for both weights with font-display: swap. Update @tailwind.config.ts to override the sans font family with BrandFont as the primary font and Inter as the fallback. Add the antialiased class to the body tag.
Frequently asked questions
How do I add a custom font to a Lovable project?
For Google Fonts, add a link tag in index.html. For local fonts, place WOFF2 files in /public/fonts/ and add @font-face rules in index.html. Then extend fontFamily in tailwind.config.ts and apply the font class to your elements or override the sans key for global usage.
Why does my custom font not appear on shadcn/ui components?
shadcn/ui components inherit the Tailwind sans font family. If you added your font as a separate key (like font-brand) instead of overriding sans, shadcn/ui still uses the default font. Override the sans key in tailwind.config.ts to make your font the global default.
What font file format should I use?
Use WOFF2. It has the best compression (30-50% smaller than WOFF), is supported by all modern browsers, and loads faster. Include a WOFF fallback only if you need to support very old browsers.
Where do I put local font files in a Lovable project?
Place them in /public/fonts/. Vite serves /public contents at the root, so /public/fonts/MyFont.woff2 is accessible at /fonts/MyFont.woff2 in your browser. Reference this path in your @font-face src rules.
How do I use different fonts for headings and body text?
Add both fonts to tailwind.config.ts with different keys (e.g., font-heading and font-body). Apply font-heading to your h1-h6 elements and font-body to paragraph text. You can also override the sans key for body and create a separate heading key.
What if I can't fix this myself?
If your font setup involves complex typography hierarchies, variable fonts, or conflicts with the shadcn/ui theme system across many components, RapidDev's engineers have configured custom font systems across 600+ Lovable projects.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your issue.
Book a free consultation