Google Fonts not working in Tailwind + Vite: @import order
Why the font-inter class exists but the text stays in the default face in a React and Vite project, and the one-line move that makes the browser download Inter.
TL;DR#
When a Google Font "does not work" in a React, Vite and Tailwind CSS project, check two things. First, the font @import url(...) must be the first line of index.css. In Tailwind v4, a font import written after @import "tailwindcss" lands behind the generated theme and preflight rules. The browser ignores it, and vite build strips it from the output, so Inter is never downloaded. Second, Tailwind v4 does not read tailwind.config.js on its own. A fontFamily.inter entry there produces no font-inter class. Declare --font-inter inside @theme, or point at the old file with @config. The swap from @vitejs/plugin-react-swc to @vitejs/plugin-react, which the Stack Overflow question accepted, changed nothing in a current reproduction.
The warnings Vite prints#
With the font import placed after @import "tailwindcss", the Vite dev server logs this line:
[vite:css][postcss] @import statements must precede all other statements (besides @charset or empty @layer) and be consecutiveA production vite build reports the same problem in a different wording, then finishes successfully:
Found 1 warning while optimizing generated CSS:
│ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
┆ ^-- @import rules must precede all rules aside from @charset and @layer statementsBoth are warnings, not errors. The page renders, the font-inter class is on the element, and DevTools shows Inter in the computed font-family. It is easy to scroll past the line and conclude that Tailwind is broken.
What the question's own files do today#
The asker's project is React with Vite and Tailwind v3 syntax: @tailwind base, a tailwind.config.js that extends fontFamily with inter: ["Inter", "sans-serif"], and the Google Fonts @import already on the first line. The index.html also loads the Tailwind Play CDN script, and vite.config.js passes tailwindcss() to css.postcss with @vitejs/plugin-react-swc.
The question's files, plus a small probe script, were reproduced on 30 October 2026, on a Windows 11 host without Docker, with Node 26.7.0, npm 11.19.0, Vite 8.3.5 and tailwindcss 3.4.19. Fonts were checked in headless Google Chrome 156.0.8078.76: a small script reads getComputedStyle(h1).fontFamily and counts the Inter faces in document.fonts. The v4 cases below used tailwindcss 4.3.3 with @tailwindcss/vite 4.3.3. Run as posted, the setup works. The build starts with the font import and contains the class:
built CSS starts with: @import "https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap";*,:before,:
font-inter rule: .font-inter{font-family:Inter,sans-serif}In the browser, the heading resolved to Inter in the production preview, with the CDN script still in place. In the dev server the 7 Inter faces were registered, but none had finished loading when the probe ran, so that run proves the import arrived, not that the file was drawn. The accepted answer blames @vitejs/plugin-react-swc. As a negative control, the build was repeated with that single import changed to @vitejs/plugin-react. Both builds produced the same file, hash for hash:
sha256: 484da531eb4eed6dec9f80cec3072957f0ee1eb59046f29c79ce007dd6543990That fits the division of work: the React plugin compiles JSX, while Tailwind and PostCSS handle the stylesheet. The reproduction cannot say why the asker's switch appeared to help in March 2024. What it does show is how the same project breaks today, once npm install tailwindcss pulls v4. That is where answer 2 (the highest-voted one) comes in.
Why it happens on Tailwind v4#
The font import ends up behind Tailwind's rules#
In v4 the three @tailwind directives become a single @import "tailwindcss", which the Tailwind Vite guide tells you to add to your CSS. If the Google Fonts line is pasted underneath it, the problem starts: that import is inlined, so the font import now follows the whole theme layer and preflight. MDN's @import reference is explicit: "An @import rule must be defined at the top of the stylesheet, before any other at-rule (except @charset and @layer) and style declarations, or it will be ignored."
The reproduction shows both halves. In development the Vite dev server warns and the probe found no Inter face. In production the rule never reaches the browser: the built CSS contained zero occurrences of googleapis. In both modes the probe counted no Inter face at all, while the class itself was fine:
font-inter rule: .font-inter{font-family:var(--font-inter)}
<pre id="probe">{"h1FontFamily":"Inter, \"sans-serif\"","interFontFacesInDocument":0,"interFacesLoadedFor400":0}</pre>The computed style says Inter because the class applied. The browser simply has no Inter to draw with, so it falls through the list. This is the case where DevTools looks right and the text looks wrong.
The JavaScript config is no longer read#
The second v4 trap is the tailwind.config.js from the question. The v4 upgrade guide states it directly: "JavaScript config files are still supported for backward compatibility, but they are no longer detected automatically in v4." With the font import correctly on line one and the config file present but unreferenced, Inter downloaded, yet the build contained no class for it:
font-inter rule: (none)The heading kept Tailwind's default font-sans stack. In v4, utilities come from theme variables: the theme documentation explains that "theme variables defined in the --font-* namespace determine all of the font-family utilities that exist in a project".
Fix on Tailwind v4#
On Tailwind v3 only the ordering rule applies: keep the font @import above @tailwind base, as the question already does. The steps below are for v4.
- Put the Google Fonts import on the first line of
src/index.css, above Tailwind:
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap');
@import "tailwindcss";- Declare the family as a theme variable in the same file, with the generic fallback unquoted:
@theme {
--font-inter: 'Inter', sans-serif;
}- If you would rather keep the v3
tailwind.config.jsfor now, skip step 2 and load the file explicitly, as the upgrade guide shows. The path is relative to the CSS file:
@config "../tailwind.config.js";- Use the Vite plugin rather than the PostCSS setup from the question. The Play CDN script tag in
index.htmlis not needed once Vite compiles Tailwind (the reproduction worked with it still in place). The Vite configuration from answer 2:
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [tailwindcss(), react()]
})- Run
npm run devand apply the class to an element:className="font-inter".
Verify the fix#
The dev server should no longer print the @import statements must precede line, and npm run build should finish without the "Found 1 warning" block. Then open the built stylesheet in dist/assets/ and search it for googleapis: one match means the import survived. In the browser, document.fonts is the reliable check, because the computed font-family shows Inter even when no file was downloaded. With the import on the first line and the unquoted fallback from step 2, the probe counted the Inter faces that the Google stylesheet declares:
<pre id="probe">{"h1FontFamily":"Inter, sans-serif","interFontFacesInDocument":7,"interFacesLoadedFor400":1}</pre>With the @config variant instead of @theme, the build should now contain .font-inter{font-family:Inter,sans-serif}.
One email a month — the latest explained errors
What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.
The quoted 'sans-serif' in answer 2#
Answer 2's theme block writes --font-inter: 'Inter', 'sans-serif';. It does not stop Inter from loading, and in the reproduction the font was applied once the import moved up. But the quotes change the meaning of the fallback. MDN's font-family reference says: "Generic family names are keywords and must not be quoted." A quoted 'sans-serif' asks for an installed font literally named sans-serif, so while Inter is still downloading (the import uses display=swap), or if Google Fonts is blocked, the browser finds no font by that name and falls back to its own default face instead of a sans-serif one. The computed style shows the difference: Inter, "sans-serif" with quotes, Inter, sans-serif without.
Loading the font from index.html instead#
A Google Fonts <link> in the <head> of index.html avoids the ordering problem entirely, because the font stylesheet is no longer part of the CSS file Tailwind processes. With the CSS reduced to @import "tailwindcss" and the @theme block, and this stylesheet tag added to the head (next to two preconnect resource hints for the Google Fonts hosts), the heading resolved to Inter in both preview and dev mode:
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet" />For self-hosted font files declared with @font-face, the failure modes are different (format hints and family names): see custom font not working in Tailwind CSS.
When the error changes after the upgrade#
Upgrading this question's project to v4 can surface a hard error before the font is even reached. The question wires Tailwind into PostCSS twice, through tailwindcss: {} in postcss.config.js and tailwindcss() in the css.postcss block of vite.config.js. Both are v3 setups, and v4 refuses the package as a PostCSS plugin: the fix is covered in Tailwind PostCSS plugin has moved, which explains why the Vite plugin replaces PostCSS in a Vite project. If vite.config.js then fails on the @tailwindcss/vite import itself, read Failed to resolve "@tailwindcss/vite": ESM only. And if the font works in npm run dev but not in the deployed build, check how dist is served first, as described in Tailwind CSS not working after Vite build.
The short version holds on both v3 and v4: Google Fonts are an ordinary CSS @import, and CSS only honours an @import at the top of a stylesheet. Tailwind v3's directives happened to leave room for the import above them, and v4's single import makes it easy to paste the font line one row too low. Put it first, define the family where v4 actually reads it, and check document.fonts rather than the computed style.
Frequently Asked Questions
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix Tailwind v4 IntelliSense not working in VS Code
Find which layer has stopped working: Tailwind project discovery, document mapping, or automatic suggestions inside JSX strings.
Fix shadcn "No Tailwind CSS configuration found" in Vite
What shadcn init actually looks for before it says Tailwind is missing, reproduced on Tailwind 3 and 4 with the one line that fixes each.
Fix: Tailwind PostCSS Plugin Has Moved (Vite + React)
The exact steps to resolve the Tailwind v4 PostCSS plugin relocation error in a Vite + React + TypeScript build.


