Styles and static files
Vite handles styles and images in the project: it bundles CSS, adds a hash to file names for caching and inserts the right addresses. All you need to do is import a file in the right place.
Global styles
The template already includes app/app.css in app/root.tsx with the line import "./app.css";. Everything you add there applies to all pages:
/* app/app.css */
.flash {
padding: 8px 12px;
background: #e6f4ea;
border-radius: 6px;
}The "Post published" flash message from the sessions lesson gets a green background. The default template also sets up Tailwind CSS — utility classes such as p-4 and text-xl can be written straight into className. If you do not need Tailwind, remove its line from app/app.css and the plugin from vite.config.ts.
Styles for one route
To load the post styles only on its page, import the file with the ?url suffix and return it from links:
// app/routes/post.tsx
import type { Route } from "./+types/post";
import postStyles from "./post.css?url";
export const links: Route.LinksFunction = () => [
{ rel: "stylesheet", href: postStyles },
];?url asks Vite for the address of the built file rather than its contents. The link tag appears in head only on post pages.
CSS modules
A file ending in .module.css becomes an object, and its class names become unique:
/* app/components/PostCard.module.css */
.card {
border: 1px solid #ddd;
padding: 16px;
}// app/components/PostCard.tsx
import styles from "./PostCard.module.css";
export function PostCard({ title }: { title: string }) {
return <div className={styles.card}>{title}</div>;
}The card class will not clash with a class of the same name in another file.
Images and the public folder
| Where the file lives | How to use it | When it fits |
|---|---|---|
app/ | import logo from "./logo.svg" and src={logo} | Images used by code |
public/ | A direct address /favicon.ico | favicon.ico, robots.txt, files with a fixed address |
An imported image gets an address with a hash, so the browser always loads the fresh version. Files from public/ are copied to the build as is.
Common mistake
Writing the path src="/public/logo.png" in code. The contents of public/ are served from the site root, so the correct address is /logo.png. With the extra /public the image is not found either in development or after the build.