Tailwind CSS
Tailwind CSS 4 configuration and custom theming.
Raypx uses Tailwind CSS 4, which configures the theme entirely in CSS rather than a JavaScript config file. There is no tailwind.config.js — all customization happens in CSS files.
Plugin Setup
The @tailwindcss/vite plugin is registered in vite.config.ts:
import tailwindcss from "@tailwindcss/vite"
export default defineConfig({
plugins: [
tailwindcss(),
// ...
],
})Style Files
Raypx has two CSS entry points:
| File | Purpose |
|---|---|
src/styles/index.css | Application styles. Imports the UI package globals. |
src/styles/docs.css | Documentation site styles. Imports Fumadocs presets. |
Application Styles (src/styles/index.css)
@import "@raypx/ui/styles/globals.css";This single import pulls in the entire theme: Tailwind base, component utilities, shadcn/ui CSS variables, and the typography plugin.
Documentation Styles (src/styles/docs.css)
@import "tailwindcss";
@import "@fumadocs/base-ui/css/shadcn.css";
@import "@fumadocs/base-ui/css/preset.css";
html {
scrollbar-gutter: stable;
}The docs site uses its own Tailwind import with Fumadocs-specific presets for the documentation layout.
Theme Configuration
All theme customization lives in packages/ui/src/styles/globals.css. This is where Tailwind 4 defines design tokens using CSS:
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@import "@fontsource-variable/inter";
@import "@fontsource-variable/manrope";
@plugin "@tailwindcss/typography";
@custom-variant dark (&:is(.dark *));
@source "../../../packages/**/*.{ts,tsx}";
@source "../../../src/**/*.{ts,tsx}";
@theme inline {
--font-sans: "Inter Variable", sans-serif;
--font-heading: "Manrope Variable", sans-serif;
--radius: 0.625rem;
/* ... more tokens ... */
}Key directives:
@plugin "@tailwindcss/typography"— enables the typography plugin for prose content.@custom-variant dark (&:is(.dark *))— dark mode is class-based, toggled by adding.darkto an ancestor element.@source— tells Tailwind where to scan for class usage. Includes bothpackages/andsrc/.
Dark / Light Mode
Raypx uses next-themes to manage theme switching. The default theme is dark (set via VITE_PUBLIC_DEFAULT_THEME).
The theme provider wraps the application and adds the .dark class to the <html> element based on the user's preference. The Tailwind @custom-variant dark directive targets this class:
@custom-variant dark (&:is(.dark *));This means dark:bg-gray-900 applies a dark background only when the .dark class is present on an ancestor.
CSS Variables (Design Tokens)
Color and spacing tokens are defined as CSS custom properties in :root (light mode) and .dark (dark mode) selectors:
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--radius: 0.625rem;
/* ... */
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
/* ... */
}All colors use the OKLCH color space for perceptual uniformity. To change the color scheme, edit these variables.
Typography Plugin
The @tailwindcss/typography plugin provides the prose class for styling long-form content like documentation pages and blog posts. It is registered via @plugin in the globals file.
Utility Class Sorting
Biome automatically sorts Tailwind utility classes in your JSX/TSX files. The useSortedClasses rule in biome.json handles this:
{
"nursery": {
"useSortedClasses": {
"level": "warn",
"fix": "safe",
"options": {
"functions": ["clsx", "cva", "cn"]
}
}
}
}Run pnpm check to auto-sort classes in all files.
Fonts
Two variable fonts are loaded via @fontsource-variable:
| Font | Variable | Usage |
|---|---|---|
| Inter | --font-sans | Body text, UI elements |
| Manrope | --font-heading | Headings |
Both fonts support variable weight and are self-hosted — no external font requests.