Raypx

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:

FilePurpose
src/styles/index.cssApplication styles. Imports the UI package globals.
src/styles/docs.cssDocumentation 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 .dark to an ancestor element.
  • @source — tells Tailwind where to scan for class usage. Includes both packages/ and src/.

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:

FontVariableUsage
Inter--font-sansBody text, UI elements
Manrope--font-headingHeadings

Both fonts support variable weight and are self-hosted — no external font requests.

On this page