Set up Master CSS in Vite
Connect Master CSS to Vite, React, Vue, React Router or TanStack Start, then verify static CSS and optional browser generation.
On this page
Add Master CSS to an application built with Vite, including React, Vue, React Router framework mode and TanStack Start. The integration generates CSS from complete class names in source. Keep the framework's existing Vite plugin and mount code; Master CSS joins that build through a shared stylesheet.
#Installation
#Add Master CSS
In an existing Vite project, run the installer from the project root with the
--frameworkvalue from the framework table. Static is the default: complete class names in source become ordinary CSS.npm create @master/css@2.0.0 -- --framework vite --yes#Check the CSS entry
The installer adds
masterCSS()to the Vite plugins and updates the stylesheet listed under Framework entries. In a plain JavaScript starter, that is:@import '@master/css';Keep this entry imported by the application. If the project uses a different filename, check the installer's output and keep the import pointed at that file. The installer does not create a framework application or replace its mount code.
#Start using Master CSS
For a plain JavaScript starter with an
#appelement, use this entry and runnpm run dev. For a framework application, use its component example below instead.
Check the installed styles
import './style.css'document.querySelector('#app').innerHTML = ` <p id="master-check" class="w-fit m(0) p-md b-solid b(1) b-line-divider r-md text-sm font-regular bg-surface-raised fg-text-strong"> Hello World </p>`#Framework entries
Choose the installer value for your application. These are the conventional starter paths; React and Vue setups can reuse another supported existing CSS entry. Without the flag, the installer detects the framework from the project.
| Framework | --framework | CSS entry |
|---|---|---|
| Vite with plain JavaScript | vite | src/style.css |
| React | react | src/index.css |
| Vue | vue | src/assets/main.css |
| React Router framework mode | react-router | app/app.css |
| TanStack Start | tanstack-start | src/styles/app.css |
#React
In a React project built with Vite, replace src/App.tsx. Keep the src/index.css import in src/main.tsx.
export default function App() { return ( <p id="master-check" className="w-fit m(0) p-md b-solid b(1) b-line-divider r-md text-sm font-regular bg-surface-raised fg-text-strong"> Hello World </p> )}#Vue
In a Vue project, replace src/App.vue. Keep the src/assets/main.css import in the application entry.
<template> <p id="master-check" class="w-fit m(0) p-md b-solid b(1) b-line-divider r-md text-sm font-regular bg-surface-raised fg-text-strong"> Hello World </p></template>#React Router
In a React Router framework mode project, the installer imports app/app.css from app/root.tsx. Replace the home route and keep it registered in app/routes.ts. Retain Links, Scripts, Outlet and the document structure in app/root.tsx; they deliver the page and its stylesheet.
export default function Home() { return ( <p id="master-check" className="w-fit m(0) p-md b-solid b(1) b-line-divider r-md text-sm font-regular bg-surface-raised fg-text-strong"> Hello World </p> )}#TanStack Start
In a TanStack Start project built with Vite, replace the index route. The installer imports src/styles/app.css from src/routes/__root.tsx, so every route loads the same CSS entry.
import { createFileRoute } from '@tanstack/react-router'export const Route = createFileRoute('/')({ component: Home})function Home() { return ( <p id="master-check" className="w-fit m(0) p-md b-solid b(1) b-line-divider r-md text-sm font-regular bg-surface-raised fg-text-strong"> Hello World </p> )}#Check the setup
Change p-md to p-lg in the source while the dev server is running. Padding should grow from 1rem to 1.5rem. Restore p-md, then build the application:
npm run buildServe the production output with the project's preview or start command. Plain Vite, React and Vue starters normally use npm run preview; React Router and TanStack Start use their configured server or deployment adapter. Check that the paragraph still has 1rem padding and that no Master CSS browser runtime is shipped in static mode.
Client-rendered applications need JavaScript to create the paragraph. For React Router or TanStack Start routes with server rendering enabled, disable JavaScript and reload to check that the server's HTML receives the same stylesheet.
If the file loads but one class is missing, keep its full name in source; see Scanning class names. If no utilities work, confirm the CSS entry is imported and the Vite configuration includes masterCSS() beside the framework plugin. If starter styles obscure the result, remove their appearance rules while keeping @import '@master/css';.
#Choose another rendering mode
Static mode is the default and needs no Master CSS startup code. Keep the CSS entry when changing modes:
| Framework | Installer option | Runtime startup |
|---|---|---|
| Vite, React, Vue | --mode runtime | Injected into index.html by the Vite plugin |
| React Router, TanStack Start | --mode runtime | A browser-only import in the root route |
Generate new classes in the browser
Run the installer with --mode runtime and your --framework value:
npm create @master/css@2.0.0 -- --framework vite --mode runtime --yesFor Vite, React and Vue, the plugin injects the runtime into index.html and emits its compiled program. Do not add a second runtime import.
React Router and TanStack Start produce their own HTML, which does not pass through Vite's index.html injection. Add a browser-only runtime import beside the stylesheet import in the existing root route, keeping its route definitions and component exports:
import './app.css'if (!import.meta.env.SSR) { void import('virtual:master-css-runtime')}import '../styles/app.css'if (!import.meta.env.SSR) { void import('virtual:master-css-runtime')}The guard keeps the virtual runtime out of server execution; load it once per document. Add the client types in a declaration file such as app/master-css.d.ts or src/master-css.d.ts:
/// <reference types="@master/css/client" />Build and preview the app, then run this in the browser console. The paragraph should gain an underline without rebuilding:
document.querySelector('#master-check').classList.add('underline')Server-rendered HTML does not include runtime-generated CSS before JavaScript runs. If the class has no effect, check the console and the emitted program request.
#Choose how to load a stylesheet
Keep the normal CSS import for a document stylesheet. Use a different request only when another consumer needs the CSS text or its URL. These requests do not replace the app's Master CSS entry or change its rendering mode.
| Request | Result and responsibility |
|---|---|
import './app.css' | Vite loads the processed stylesheet for the document. |
import styles from './Card.module.css' | Vite loads scoped CSS and returns the local class-name mapping. |
import css from './app.css?inline' | Returns processed CSS text without injecting it; the consumer must attach it. |
import source from './app.css?raw' | Returns authored source, including any Master directives. It is not browser-ready CSS. |
import href from './local.css?url' | Returns a URL; attach it as a stylesheet link when the document needs those styles. |
For example, insert trusted build output into a document you own:
import css from './app.css?inline'const style = document.createElement('style')style.textContent = cssdocument.head.append(style)Processed text can still contain imports. Use CSSStyleSheet.replaceSync() only with import-free output; it does not load imported stylesheets. For a shadow root, follow the Lit setup, including its stylesheet order and asset-base requirements.
#Sass and CSS Modules
Keep the project's Sass dependency and Vite preprocessing options. Write the Master CSS entry import as a CSS URL import so Sass leaves it for Master CSS:
@import url("@master/css");Resolved Sass partials retain their resource directories. Source maps connect diagnostics to the original file where possible; generated or unmapped content can only identify a preprocessed location. Keep Master mixin definitions in .css, or use the Sass interoperability pattern.
CSS Modules retain their scoped exports and composes relationships. Native declarations can use the project's definitions without importing the global output again. Framework HMR or the consuming module must accept changed class-name exports to update them without a page reload. ?inline returns scoped CSS text; ?raw returns the original source. Vite 8.3.5 rejects ?url requests for .module.css and .module.scss; do not use that path for a module stylesheet.
#Check the deployed assets
Deploy the whole production output, including retained child stylesheets, images, fonts and any runtime program. Master CSS preserves import media, supports and layer qualifiers, and rewrites resource URLs from their original source owner. An inline string can therefore require separate assets too; the Imports contract explains the boundary.
For an SSR ?inline consumer, URLs use the configured public base. Vite does not emit SSR assets by default: deploy the matching client build's assets, or enable build.ssrEmitAssets when the server build must publish them. Inspect the served response and Network panel after moving the build to its deployment location; an in-place build cannot establish URL portability.
During development, deleting a referenced resource reports a compilation error; already published resource versions can remain available until that server context closes. Restore the dependency and confirm that its consumer updates and the error clears. A still-styled page alone does not prove that the latest compilation succeeded.

