Configuring Tailwind CSS 4 with @tailwindcss/vite Plugin in OpenCut: Complete Setup Guide
OpenCut configures Tailwind CSS 4 by registering the @tailwindcss/vite plugin in apps/web/vite.config.ts, importing Tailwind directives via @import syntax in apps/web/src/styles.css, and using a cn utility combining clsx and tailwind-merge for safe class composition.
OpenCut is an open-source video editing application built with React and Vite. Configuring Tailwind CSS 4 with the @tailwindcss/vite plugin in OpenCut requires coordinated setup across the Vite configuration, package dependencies, and global stylesheet to leverage the new JIT compiler architecture and zero-configuration approach.
How Tailwind CSS 4 Integrates with Vite in OpenCut
Tailwind CSS 4 moves from a PostCSS plugin model to a standalone toolchain. In OpenCut, this integration is orchestrated through three core configuration layers that enable automatic utility generation and native Vite optimization.
Vite Configuration File
The primary integration point is apps/web/vite.config.ts, where the @tailwindcss/vite plugin is imported and added to the plugins array. Unlike Tailwind CSS 3, which required a postcss.config.js file, version 4 operates as a first-class Vite plugin.
// apps/web/vite.config.ts
import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';
// ... other imports
export default defineConfig({
plugins: [
tailwindcss(), // Activates Tailwind CSS 4 JIT compiler
// ... other plugins
],
});
By calling tailwindcss() within the configuration, the plugin automatically watches source files and generates only the CSS utilities actually used in the application bundle. This eliminates the need for separate PostCSS configuration while providing faster incremental builds.
Package Dependencies
The required packages are declared in apps/web/package.json, specifying Tailwind CSS 4 and its Vite integration alongside utility libraries for class name management.
tailwindcss@^4.1.18– The core Tailwind CSS engine.@tailwindcss/vite@^4.1.18– The official Vite plugin for Tailwind 4.tailwind-merge@^3.5.0– For resolving conflicting Tailwind classes.clsx– For conditional class name construction.
Global Stylesheet Configuration
The entry CSS file at apps/web/src/styles.css imports Tailwind CSS 4 using the new module-based @import syntax rather than traditional @tailwind directives. This file also defines custom variants and imports optional animation libraries.
/* apps/web/src/styles.css */
@import 'tailwindcss';
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@import "@fontsource-variable/inter";
@custom-variant dark (&:is(.dark *));
The @custom-variant dark declaration creates a dark mode variant that automatically scopes utilities to descendants of any element with the .dark class. This enables straightforward theme toggling without manually prefixing every utility with dark:.
Class Name Composition Utilities
OpenCut implements a standardized approach to combining Tailwind classes safely. The cn utility function in apps/web/src/lib/utils.ts wraps clsx for conditional logic and tailwind-merge for conflict resolution.
// apps/web/src/lib/utils.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Components use this helper to merge base styles with conditional overrides. This ensures that later classes take precedence when conflicts occur, such as when overriding bg-muted with bg-primary, preventing invalid CSS from duplicate property declarations.
Practical Implementation Examples
Complete Vite Configuration
The full Vite setup includes additional plugins for React and cloud deployment, with Tailwind CSS 4 integrated seamlessly into the pipeline:
// apps/web/vite.config.ts
import { defineConfig } from 'vite';
import viteReact from '@vitejs/plugin-react';
import tailwindcss from '@tailwindcss/vite';
import { cloudflare } from '@cloudflare/vite-plugin';
import { devtools } from '@tanstack/devtools-vite';
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
export default defineConfig({
resolve: { tsconfigPaths: true },
plugins: [
devtools(),
cloudflare({ viteEnvironment: { name: 'ssr' } }),
tailwindcss(), // Tailwind CSS 4 integration
tanstackStart(),
viteReact(),
],
});
Using the cn Helper in Components
React components leverage the cn utility imported from #/lib/utils (aliased to apps/web/src/lib/utils.ts) to handle dynamic styling:
// Example usage in a component
import { cn } from '#/lib/utils';
export function Button({ active }: { active: boolean }) {
return (
<button
className={cn(
"p-2 rounded-md transition-colors",
active ? "bg-primary text-primary-foreground" : "bg-muted"
)}
>
Click me
</button>
);
}
Summary
- Zero-configuration setup: Tailwind CSS 4 integrates directly into Vite via the
@tailwindcss/viteplugin inapps/web/vite.config.ts, removing the need for PostCSS configuration files. - Modern import syntax: The global stylesheet at
apps/web/src/styles.cssuses@import 'tailwindcss'to load utilities and defines custom dark mode variants via@custom-variant. - Dependency management: Core packages including
tailwindcss@^4.1.18,@tailwindcss/vite@^4.1.18,tailwind-merge, andclsxare declared inapps/web/package.json. - Safe class merging: The
cnutility function inapps/web/src/lib/utils.tscombinesclsxandtailwind-mergeto prevent conflicting utility classes in components while supporting conditional logic.
Frequently Asked Questions
How does the @tailwindcss/vite plugin differ from PostCSS-based Tailwind setups?
The @tailwindcss/vite plugin operates as a standalone Vite plugin rather than a PostCSS plugin, enabling Tailwind CSS 4 to run its own JIT compiler directly within Vite's build pipeline. This eliminates the need for a postcss.config.js file and provides faster incremental builds by watching source files directly through Vite's module graph rather than the file system.
What is the cn utility function used for in OpenCut?
The cn function in apps/web/src/lib/utils.ts is a composition helper that combines clsx for conditional class name logic with tailwind-merge for resolving conflicting Tailwind utilities. It ensures that when multiple classes target the same CSS property, the last specified class takes precedence without manual string manipulation, preventing invalid CSS output.
How is dark mode implemented in OpenCut's Tailwind configuration?
Dark mode is implemented using a custom variant defined in apps/web/src/styles.css via the @custom-variant dark (&:is(.dark *)); directive. This creates a .dark class selector that automatically scopes dark mode utilities to descendant elements, allowing developers to toggle themes by adding or removing the .dark class on a parent container.
Where are Tailwind CSS 4 dependencies declared in the project?
All Tailwind CSS 4 related dependencies are declared in apps/web/package.json, including the core tailwindcss package at version ^4.1.18, the Vite integration plugin @tailwindcss/vite at ^4.1.18, and helper libraries tailwind-merge and clsx for class name management and conflict resolution.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →