Tailwind CSS
Styling with Tailwind CSS v4 in your matt-init project
Configuration
No Config File Needed
Unlike previous versions, Tailwind v4 doesn't require a separate configuration file. Everything is handled through CSS:
/* Configure Tailwind directly in CSS */
@import "tailwindcss";
/* Custom spacing scale */
@theme {
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
--spacing-xl: 4rem;
}
Using Tailwind Classes
Basic Styling
// Basic utility classes
<div className="bg-white p-4 rounded-lg shadow-md">
<h1 className="text-2xl font-bold text-gray-900">
Hello World
</h1>
<p className="text-gray-600 mt-2">
This is styled with Tailwind CSS
</p>
</div>
Responsive Design
// Mobile-first responsive design
<div className="
w-full
md:w-1/2
lg:w-1/3
xl:w-1/4
p-4
sm:p-6
lg:p-8
">
<img
className="w-full h-48 sm:h-64 lg:h-72 object-cover rounded-lg"
src="/image.jpg"
alt="Responsive image"
/>
</div>
Dark Mode
// Dark mode utilities
<div className="
bg-white dark:bg-gray-800
text-gray-900 dark:text-white
border border-gray-200 dark:border-gray-700
">
<h2 className="text-xl font-semibold text-gray-800 dark:text-gray-100">
Dark Mode Ready
</h2>
</div>
Dark Mode Implementation
Note: Dark mode is not properly implemented in matt-init quite yet. It's very half baked at the moment. This is all subject to change.
System Preference Detection
// components/theme-toggle.tsx
"use client";
import { useEffect, useState } from "react";
export function ThemeToggle() {
const [isDark, setIsDark] = useState(false);
useEffect(() => {
// Check system preference
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
setIsDark(mediaQuery.matches);
// Listen for changes
const handler = (e: MediaQueryListEvent) => setIsDark(e.matches);
mediaQuery.addEventListener("change", handler);
return () => mediaQuery.removeEventListener("change", handler);
}, []);
useEffect(() => {
// Apply dark class to document
if (isDark) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}, [isDark]);
return (
<button
onClick={() => setIsDark(!isDark)}
className="p-2 rounded-md bg-gray-200 dark:bg-gray-700"
>
{isDark ? "๐" : "๐"}
</button>
);
}
Persistent Theme Storage
"use client";
import { useEffect, useState } from "react";
type Theme = "light" | "dark" | "system";
export function useTheme() {
const [theme, setTheme] = useState<Theme>("system");
useEffect(() => {
const stored = localStorage.getItem("theme") as Theme;
if (stored) setTheme(stored);
}, []);
useEffect(() => {
localStorage.setItem("theme", theme);
if (theme === "system") {
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const applyTheme = () => {
document.documentElement.classList.toggle("dark", mediaQuery.matches);
};
applyTheme();
mediaQuery.addEventListener("change", applyTheme);
return () => mediaQuery.removeEventListener("change", applyTheme);
} else {
document.documentElement.classList.toggle("dark", theme === "dark");
}
}, [theme]);
return { theme, setTheme };
}