Initial commit
This commit is contained in:
14
.claude-plugin/plugin.json
Normal file
14
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "tailwind-4",
|
||||||
|
"description": "Tailwind CSS v4 patterns: CSS-first config, oklch colors, container queries, @utility directive",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Design Session with Claude Code"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"hooks": [
|
||||||
|
"./hooks"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# tailwind-4
|
||||||
|
|
||||||
|
Tailwind CSS v4 patterns: CSS-first config, oklch colors, container queries, @utility directive
|
||||||
53
hooks/hooks.json
Normal file
53
hooks/hooks.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"hooks": {
|
||||||
|
"SessionStart": [
|
||||||
|
{
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/init-session.sh",
|
||||||
|
"timeout": 1000,
|
||||||
|
"description": "Initialize session state for skill recommendations"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PreToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Read|Write|Edit",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/recommend-skills.sh",
|
||||||
|
"timeout": 1000,
|
||||||
|
"description": "Recommend relevant Tailwind v4 skills based on file patterns"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"matcher": "Write",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-config.sh",
|
||||||
|
"timeout": 1000,
|
||||||
|
"description": "Block deprecated tailwind.config.js files in Tailwind v4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"PostToolUse": [
|
||||||
|
{
|
||||||
|
"matcher": "Write|Edit",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/validate-tailwind-v4.sh",
|
||||||
|
"timeout": 5000,
|
||||||
|
"description": "Validate Tailwind v4 patterns and suggest fixes"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
105
plugin.lock.json
Normal file
105
plugin.lock.json
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:djankies/claude-configs:tailwind-4",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "a18d0811809f9a00e5fae6a690f1553fa0797c12",
|
||||||
|
"treeHash": "419af0c5882d739b7013b72a661c8eaa04711332393cec717af929d0415fa41e",
|
||||||
|
"generatedAt": "2025-11-28T10:16:30.280280Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "tailwind-4",
|
||||||
|
"description": "Tailwind CSS v4 patterns: CSS-first config, oklch colors, container queries, @utility directive",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "42897bffbfaaa4c3744b9f69c419a63cc9104cbe8fb51f60b722d54693a7cab8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "hooks/hooks.json",
|
||||||
|
"sha256": "4c256357ff8ec095214f0d311e54557a5af20e572cf5e2c7395070bf213d08ee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "84d2c0695cd1940d7686789c2e894a370968d3981f51f5cd6f458cb056137b1c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/creating-custom-utilities/SKILL.md",
|
||||||
|
"sha256": "db188b2620c91f8cd8a92a580c42120b96b0e0cbc33146e59d2ab82aee17035a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/configuring-tailwind-v4/SKILL.md",
|
||||||
|
"sha256": "c069b146429ebe7e68e76b535a8effcdc10ed3a357550049abf0fd71f9fc29ee"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/configuring-tailwind-v4/references/nextjs-setup.md",
|
||||||
|
"sha256": "59755429d76eee68d51c560c640d7a623ed30f9099ba2bc666c94c44764272fd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/configuring-tailwind-v4/references/vite-setup.md",
|
||||||
|
"sha256": "b31177502b1a96edb7aed256da05fc5bf11b265a314c9cf4d19d739ad51ecbde"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/configuring-tailwind-v4/references/postcss-setup.md",
|
||||||
|
"sha256": "3f847c3161b86d3032b2ee47ad4a5ec498efe4340f6d1ad99b5a363e0cc7a36a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/using-theme-variables/SKILL.md",
|
||||||
|
"sha256": "7327b3f4d6058aa6d87bad4477d2c5e765311acb61523ab72342f3c84c99b6d7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/using-theme-variables/references/namespace-reference.md",
|
||||||
|
"sha256": "aa3492dbeccaebc4538cef607f66c7d771b17506220fc65b6a4e31d6d7416022"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/using-theme-variables/references/color-conversion.md",
|
||||||
|
"sha256": "96531fadf4315046a15c72f8b6fa8070c106f8337eef86faeaac636208489729"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/reviewing-tailwind-patterns/SKILL.md",
|
||||||
|
"sha256": "d0c41d56b526381efa56a70a7e705376293ef9d58f7c93340a4d6bb2335329d9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/handling-animations/SKILL.md",
|
||||||
|
"sha256": "ad5cd945e64c2d56d44d138a5cc03c15a12166d4a9f1fd603c74bdd4ab4520e0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/handling-animations/references/animation-library.md",
|
||||||
|
"sha256": "905656e759fdfaa31f68476fd9ef0c3ce04385f8fcb22072fd71361013b63614"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/migrating-from-v3/SKILL.md",
|
||||||
|
"sha256": "2bf2744e271aa40308d3da5a674ece7678bb9f73bd0f29890dbeb01b4261b13b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/migrating-from-v3/references/breaking-changes.md",
|
||||||
|
"sha256": "f454d4a08774a9297cb7761813ba3c8461e8f2a90bae5d7c1d78262c94f555ed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/migrating-from-v3/references/migration-checklist.md",
|
||||||
|
"sha256": "723ff5da73470dc53739d73fe285139e13592e7e157366900941b9e14774990a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/using-container-queries/SKILL.md",
|
||||||
|
"sha256": "3bd3d9092809a8c503f80da51f64489e60215c4f63fa6da3d81f271d5e24d58c"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "419af0c5882d739b7013b72a661c8eaa04711332393cec717af929d0415fa41e"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
172
skills/configuring-tailwind-v4/SKILL.md
Normal file
172
skills/configuring-tailwind-v4/SKILL.md
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
---
|
||||||
|
name: configuring-tailwind-v4
|
||||||
|
description: Configure Tailwind CSS v4 using Vite plugin, PostCSS, or CLI with CSS-first configuration via @import and @theme directives. Use when setting up new projects or migrating build tools.
|
||||||
|
allowed-tools: Read, Write, Edit, Grep, Glob, Bash
|
||||||
|
---
|
||||||
|
|
||||||
|
# Configuring Tailwind v4
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Configure Tailwind CSS v4 using modern CSS-first configuration. Tailwind v4 eliminates JavaScript configuration files in favor of CSS-based setup using `@import` and `@theme` directives.
|
||||||
|
|
||||||
|
## Installation Methods
|
||||||
|
|
||||||
|
### Vite Projects (Recommended)
|
||||||
|
|
||||||
|
**Step 1: Install Dependencies**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/vite
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Configure Vite Plugin**
|
||||||
|
|
||||||
|
Add the Tailwind plugin to `vite.config.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react(), tailwindcss()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Import Tailwind in CSS**
|
||||||
|
|
||||||
|
Create or update your main CSS file (e.g., `src/index.css`):
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostCSS Projects
|
||||||
|
|
||||||
|
**Step 1: Install Dependencies**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Configure PostCSS**
|
||||||
|
|
||||||
|
Create `postcss.config.js`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Import Tailwind in CSS**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
```
|
||||||
|
|
||||||
|
### CLI Usage
|
||||||
|
|
||||||
|
**Step 1: Install CLI**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/cli
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 2: Create Input CSS**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3: Run Build Command**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @tailwindcss/cli -i input.css -o output.css --watch
|
||||||
|
```
|
||||||
|
|
||||||
|
## CSS-First Configuration
|
||||||
|
|
||||||
|
Tailwind v4 uses the `@theme` directive for all customization:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-display: 'Satoshi', 'sans-serif';
|
||||||
|
--font-body: 'Inter', 'sans-serif';
|
||||||
|
|
||||||
|
--color-brand-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-brand-accent: oklch(0.75 0.22 320);
|
||||||
|
|
||||||
|
--breakpoint-3xl: 120rem;
|
||||||
|
--breakpoint-4xl: 160rem;
|
||||||
|
|
||||||
|
--spacing-18: 4.5rem;
|
||||||
|
--spacing-72: 18rem;
|
||||||
|
|
||||||
|
--radius-4xl: 2rem;
|
||||||
|
|
||||||
|
--shadow-brutal: 8px 8px 0 0 rgb(0 0 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatic Content Detection
|
||||||
|
|
||||||
|
Template files are discovered automatically using built-in heuristics. No content array configuration required. Files in `.gitignore` are automatically excluded.
|
||||||
|
|
||||||
|
**Manual Source Control (when needed):**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@source "../node_modules/@my-company/ui-lib";
|
||||||
|
@source "./legacy-components";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Exclude paths:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@source not "./legacy";
|
||||||
|
@source not "./docs";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Disable automatic detection:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss' source(none);
|
||||||
|
@source "./src";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key Differences from v3
|
||||||
|
|
||||||
|
| v3 | v4 |
|
||||||
|
|---|---|
|
||||||
|
| `tailwind.config.js` | CSS `@theme` directive |
|
||||||
|
| `@tailwind base;` | `@import 'tailwindcss';` |
|
||||||
|
| `content: []` array | Automatic detection |
|
||||||
|
| `postcss-tailwindcss` | `@tailwindcss/postcss` |
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- Full builds: **3.78x faster** than v3
|
||||||
|
- Incremental rebuilds with new CSS: **8.8x faster**
|
||||||
|
- Incremental rebuilds without new CSS: **182x faster**
|
||||||
|
|
||||||
|
## Browser Requirements
|
||||||
|
|
||||||
|
Tailwind v4 requires:
|
||||||
|
- Safari 16.4+
|
||||||
|
- Chrome 111+
|
||||||
|
- Firefox 128+
|
||||||
|
|
||||||
|
Projects requiring older browser support must stay on v3.4.
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- references/vite-setup.md - Complete Vite configuration examples
|
||||||
|
- references/postcss-setup.md - PostCSS configuration patterns
|
||||||
|
- references/nextjs-setup.md - Next.js specific setup
|
||||||
373
skills/configuring-tailwind-v4/references/nextjs-setup.md
Normal file
373
skills/configuring-tailwind-v4/references/nextjs-setup.md
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
# Next.js Setup Guide
|
||||||
|
|
||||||
|
## Next.js 15+ with App Router
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx create-next-app@latest my-app
|
||||||
|
cd my-app
|
||||||
|
npm install tailwindcss @tailwindcss/postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**postcss.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**app/globals.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-secondary: oklch(0.75 0.22 320);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**app/layout.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import type { Metadata } from 'next';
|
||||||
|
import { Geist, Geist_Mono } from 'next/font/google';
|
||||||
|
import './globals.css';
|
||||||
|
|
||||||
|
const geistSans = Geist({
|
||||||
|
variable: '--font-geist-sans',
|
||||||
|
subsets: ['latin'],
|
||||||
|
});
|
||||||
|
|
||||||
|
const geistMono = Geist_Mono({
|
||||||
|
variable: '--font-geist-mono',
|
||||||
|
subsets: ['latin'],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: 'My App',
|
||||||
|
description: 'Built with Next.js and Tailwind CSS v4',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: Readonly<{
|
||||||
|
children: React.ReactNode;
|
||||||
|
}>) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**app/page.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<main className="flex min-h-screen flex-col items-center justify-center p-24">
|
||||||
|
<h1 className="text-4xl font-bold text-primary">
|
||||||
|
Next.js + Tailwind v4
|
||||||
|
</h1>
|
||||||
|
<p className="mt-4 text-lg text-gray-600 dark:text-gray-300">
|
||||||
|
CSS-first configuration with @theme directive
|
||||||
|
</p>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pages Router Setup
|
||||||
|
|
||||||
|
**pages/_app.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import type { AppProps } from 'next/app';
|
||||||
|
import '@/styles/globals.css';
|
||||||
|
|
||||||
|
export default function App({ Component, pageProps }: AppProps) {
|
||||||
|
return <Component {...pageProps} />;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**styles/globals.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**pages/index.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen items-center justify-center">
|
||||||
|
<h1 className="text-4xl font-bold text-primary">
|
||||||
|
Next.js Pages Router + Tailwind v4
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dark Mode Setup
|
||||||
|
|
||||||
|
**app/layout.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import './globals.css';
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html lang="en" className="dark">
|
||||||
|
<body className="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
|
||||||
|
{children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dynamic dark mode with next-themes:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install next-themes
|
||||||
|
```
|
||||||
|
|
||||||
|
**app/providers.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { ThemeProvider } from 'next-themes';
|
||||||
|
|
||||||
|
export function Providers({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||||
|
{children}
|
||||||
|
</ThemeProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**app/layout.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Providers } from './providers';
|
||||||
|
import './globals.css';
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html lang="en" suppressHydrationWarning>
|
||||||
|
<body>
|
||||||
|
<Providers>{children}</Providers>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Component Library Integration
|
||||||
|
|
||||||
|
**Shared theme across apps:**
|
||||||
|
|
||||||
|
**packages/ui/theme.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--*: initial;
|
||||||
|
|
||||||
|
--font-sans: 'Inter', sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-secondary: oklch(0.75 0.22 320);
|
||||||
|
--color-success: oklch(0.72 0.15 142);
|
||||||
|
--color-warning: oklch(0.78 0.18 60);
|
||||||
|
--color-error: oklch(0.65 0.22 25);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**apps/web/app/globals.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
@import '@my-company/ui/theme.css';
|
||||||
|
```
|
||||||
|
|
||||||
|
**postcss.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## TypeScript Component Example
|
||||||
|
|
||||||
|
**components/Button.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { ButtonHTMLAttributes, forwardRef } from 'react';
|
||||||
|
|
||||||
|
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
|
variant?: 'primary' | 'secondary' | 'outline';
|
||||||
|
size?: 'sm' | 'md' | 'lg';
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||||
|
({ variant = 'primary', size = 'md', className = '', children, ...props }, ref) => {
|
||||||
|
const baseStyles = 'rounded-lg font-medium transition-colors';
|
||||||
|
|
||||||
|
const variantStyles = {
|
||||||
|
primary: 'bg-primary text-white hover:opacity-90',
|
||||||
|
secondary: 'bg-secondary text-white hover:opacity-90',
|
||||||
|
outline: 'border-2 border-primary text-primary hover:bg-primary hover:text-white',
|
||||||
|
};
|
||||||
|
|
||||||
|
const sizeStyles = {
|
||||||
|
sm: 'px-3 py-1.5 text-sm',
|
||||||
|
md: 'px-4 py-2 text-base',
|
||||||
|
lg: 'px-6 py-3 text-lg',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
ref={ref}
|
||||||
|
className={`${baseStyles} ${variantStyles[variant]} ${sizeStyles[size]} ${className}`}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Button.displayName = 'Button';
|
||||||
|
|
||||||
|
export default Button;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server Components with Tailwind
|
||||||
|
|
||||||
|
**app/components/Card.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface CardProps {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Card({ title, description, children }: CardProps) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-lg border border-gray-200 bg-white p-6 shadow-md dark:border-gray-700 dark:bg-gray-800">
|
||||||
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-white">
|
||||||
|
{title}
|
||||||
|
</h2>
|
||||||
|
<p className="mt-2 text-gray-600 dark:text-gray-300">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
{children && <div className="mt-4">{children}</div>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment-Specific Styling
|
||||||
|
|
||||||
|
**app/globals.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
@apply antialiased;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
**next.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const nextConfig = {
|
||||||
|
experimental: {
|
||||||
|
optimizeCss: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Production build:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NODE_ENV=production npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
**Vercel:**
|
||||||
|
|
||||||
|
No additional configuration needed. Vercel automatically detects PostCSS config.
|
||||||
|
|
||||||
|
**Self-hosted:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
**Docker:**
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:20-alpine AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /app/.next ./.next
|
||||||
|
COPY --from=builder /app/public ./public
|
||||||
|
COPY --from=builder /app/package*.json ./
|
||||||
|
RUN npm ci --production
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["npm", "start"]
|
||||||
|
```
|
||||||
307
skills/configuring-tailwind-v4/references/postcss-setup.md
Normal file
307
skills/configuring-tailwind-v4/references/postcss-setup.md
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
# PostCSS Setup Examples
|
||||||
|
|
||||||
|
## Basic PostCSS Configuration
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**postcss.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**input.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## CommonJS Format
|
||||||
|
|
||||||
|
**postcss.config.cjs:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next.js Integration
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**postcss.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**app/globals.css or styles/globals.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: var(--font-geist-sans);
|
||||||
|
--font-mono: var(--font-geist-mono);
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**app/layout.tsx:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import './globals.css';
|
||||||
|
|
||||||
|
export default function RootLayout({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Webpack Integration
|
||||||
|
|
||||||
|
**webpack.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
'css-loader',
|
||||||
|
{
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
postcssOptions: {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom PostCSS Plugins
|
||||||
|
|
||||||
|
**Note:** Tailwind v4 replaces the need for `postcss-import` and `autoprefixer`.
|
||||||
|
|
||||||
|
**postcss.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build Scripts
|
||||||
|
|
||||||
|
**package.json:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"scripts": {
|
||||||
|
"dev": "postcss src/input.css -o dist/output.css --watch",
|
||||||
|
"build": "NODE_ENV=production postcss src/input.css -o dist/output.css"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Angular Integration
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**Create postcss.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**angular.json:**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"my-app": {
|
||||||
|
"architect": {
|
||||||
|
"build": {
|
||||||
|
"options": {
|
||||||
|
"postcssConfig": "postcss.config.js",
|
||||||
|
"styles": ["src/styles.css"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**src/styles.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nuxt 3 Integration
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**nuxt.config.ts:**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
export default defineNuxtConfig({
|
||||||
|
postcss: {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**assets/css/main.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**app.vue:**
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<template>
|
||||||
|
<NuxtPage />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import '@/assets/css/main.css';
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gatsby Integration
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss @tailwindcss/postcss gatsby-plugin-postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**gatsby-config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
plugins: ['gatsby-plugin-postcss'],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**postcss.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**src/styles/global.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**gatsby-browser.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import './src/styles/global.css';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
**Module parse failed: Unexpected character '@'**
|
||||||
|
|
||||||
|
Ensure PostCSS is configured correctly and using `@tailwindcss/postcss`:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Styles not applying**
|
||||||
|
|
||||||
|
Check that:
|
||||||
|
1. CSS import is present: `@import "tailwindcss";`
|
||||||
|
2. PostCSS config uses correct plugin
|
||||||
|
3. Template files aren't in `.gitignore`
|
||||||
|
4. Class names are complete strings
|
||||||
|
|
||||||
|
**Production builds missing styles**
|
||||||
|
|
||||||
|
Set `NODE_ENV=production`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NODE_ENV=production npm run build
|
||||||
|
```
|
||||||
212
skills/configuring-tailwind-v4/references/vite-setup.md
Normal file
212
skills/configuring-tailwind-v4/references/vite-setup.md
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
# Vite Setup Examples
|
||||||
|
|
||||||
|
## Basic React + Vite Setup
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm create vite@latest my-app -- --template react
|
||||||
|
cd my-app
|
||||||
|
npm install tailwindcss @tailwindcss/vite
|
||||||
|
```
|
||||||
|
|
||||||
|
**vite.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react(), tailwindcss()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**src/index.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
--font-sans: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**src/main.jsx:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom/client';
|
||||||
|
import App from './App';
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vue + Vite Setup
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm create vite@latest my-app -- --template vue
|
||||||
|
cd my-app
|
||||||
|
npm install tailwindcss @tailwindcss/vite
|
||||||
|
```
|
||||||
|
|
||||||
|
**vite.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue(), tailwindcss()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**src/style.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 142);
|
||||||
|
--font-sans: 'Roboto', sans-serif;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Svelte + Vite Setup
|
||||||
|
|
||||||
|
**Install dependencies:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm create vite@latest my-app -- --template svelte
|
||||||
|
cd my-app
|
||||||
|
npm install tailwindcss @tailwindcss/vite
|
||||||
|
```
|
||||||
|
|
||||||
|
**vite.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [svelte(), tailwindcss()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**src/app.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multi-Environment Configuration
|
||||||
|
|
||||||
|
**Development with watch mode:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig(({ mode }) => ({
|
||||||
|
plugins: [
|
||||||
|
react(),
|
||||||
|
tailwindcss({
|
||||||
|
watch: mode === 'development',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monorepo Setup
|
||||||
|
|
||||||
|
**Root vite.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react(), tailwindcss()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@ui': '/packages/ui/src',
|
||||||
|
'@shared': '/packages/shared/src',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Root CSS with package sources:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@source "../packages/ui";
|
||||||
|
@source "../packages/shared";
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Build Output
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react(), tailwindcss()],
|
||||||
|
build: {
|
||||||
|
outDir: 'dist',
|
||||||
|
cssCodeSplit: true,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
assetFileNames: 'assets/[name].[hash][extname]',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
**Exclude unnecessary directories:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@source not "./docs";
|
||||||
|
@source not "./legacy";
|
||||||
|
@source not "./scripts";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Production build:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
NODE_ENV=production npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build time monitoring:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
time npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected performance:
|
||||||
|
- Full builds: ~100ms
|
||||||
|
- Incremental rebuilds: ~5ms
|
||||||
|
- No-change rebuilds: ~192µs
|
||||||
423
skills/creating-custom-utilities/SKILL.md
Normal file
423
skills/creating-custom-utilities/SKILL.md
Normal file
@@ -0,0 +1,423 @@
|
|||||||
|
---
|
||||||
|
name: creating-custom-utilities
|
||||||
|
description: Create custom utilities with @utility directive supporting static utilities, functional utilities with values, theme-based utilities, and multi-value utilities. Use when extending Tailwind with custom CSS properties or patterns.
|
||||||
|
allowed-tools: Read, Write, Edit, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Creating Custom Utilities
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
The `@utility` directive creates custom utility classes with full variant support (hover, focus, responsive, etc.). This is the proper way to extend Tailwind v4 with custom utilities.
|
||||||
|
|
||||||
|
## Static Utilities
|
||||||
|
|
||||||
|
Define utilities with fixed values:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility content-auto {
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility content-hidden {
|
||||||
|
content-visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility text-balance {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility text-pretty {
|
||||||
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility bg-glass {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="content-auto hover:content-hidden"></div>
|
||||||
|
<p class="text-balance lg:text-pretty"></p>
|
||||||
|
<div class="bg-glass"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Static utilities work with all variants automatically.
|
||||||
|
|
||||||
|
## Functional Utilities with Integer Values
|
||||||
|
|
||||||
|
Create utilities that accept numeric values:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility mt-* {
|
||||||
|
margin-top: calc(0.25rem * --value(integer));
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility truncate-* {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: --value(integer);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility text-stroke-* {
|
||||||
|
-webkit-text-stroke-width: --value(integer) px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="mt-5"></div>
|
||||||
|
<p class="truncate-3"></p>
|
||||||
|
<h1 class="text-stroke-2"></h1>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--value(integer)` function extracts the numeric value from the class name.
|
||||||
|
|
||||||
|
## Theme-Based Utilities
|
||||||
|
|
||||||
|
Reference theme variables using `--value(--namespace- *)`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--tab-size-2: 2;
|
||||||
|
--tab-size-4: 4;
|
||||||
|
--tab-size-8: 8;
|
||||||
|
--tab-size-github: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility tab-* {
|
||||||
|
tab-size: --value(--tab-size- *);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<pre class="tab-2"><code>...</code></pre>
|
||||||
|
<pre class="tab-github"><code>...</code></pre>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Another example:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--aspect-square: 1 / 1;
|
||||||
|
--aspect-video: 16 / 9;
|
||||||
|
--aspect-portrait: 3 / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility aspect-* {
|
||||||
|
aspect-ratio: --value(--aspect- *);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<img class="aspect-square" />
|
||||||
|
<video class="aspect-video" />
|
||||||
|
<div class="aspect-portrait"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multi-Value Utilities
|
||||||
|
|
||||||
|
Create utilities that accept multiple value types:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility text-stroke-* {
|
||||||
|
-webkit-text-stroke-width: --value(integer) px;
|
||||||
|
-webkit-text-stroke-color: --value(--color- *);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h1 class="text-stroke-2-blue-500">Stroked text</h1>
|
||||||
|
<h1 class="text-stroke-1-primary">Stroked with theme color</h1>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Another example:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--blur-sm: 4px;
|
||||||
|
--blur-md: 8px;
|
||||||
|
--blur-lg: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility backdrop-blur-* {
|
||||||
|
backdrop-filter: blur(--value(--blur- *));
|
||||||
|
backdrop-filter: blur(--value(integer) px);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="backdrop-blur-sm"></div>
|
||||||
|
<div class="backdrop-blur-12"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Arbitrary Values Support
|
||||||
|
|
||||||
|
Support both theme values and arbitrary values:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility tab-* {
|
||||||
|
tab-size: --value(integer);
|
||||||
|
tab-size: --value([integer]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<pre class="tab-4">Theme value</pre>
|
||||||
|
<pre class="tab-[12]">Arbitrary value</pre>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `--value([integer])` function enables arbitrary value syntax with square brackets.
|
||||||
|
|
||||||
|
## Complex Utility Examples
|
||||||
|
|
||||||
|
### Gradient Text
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility text-gradient-* {
|
||||||
|
background: linear-gradient(to right, --value(--color- *), --value(--color- *, 2));
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<h1 class="text-gradient-blue-500-purple-600">Gradient text</h1>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Grid Template Columns
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility grid-cols-* {
|
||||||
|
grid-template-columns: repeat(--value(integer), minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="grid grid-cols-3"></div>
|
||||||
|
<div class="grid grid-cols-5"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Line Clamp
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility line-clamp-* {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: --value(integer);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility line-clamp-none {
|
||||||
|
display: block;
|
||||||
|
-webkit-box-orient: horizontal;
|
||||||
|
-webkit-line-clamp: none;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="line-clamp-2 lg:line-clamp-3 xl:line-clamp-none"></p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Spacing Scale
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--spacing-base: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility gap-* {
|
||||||
|
gap: calc(var(--spacing-base) * --value(integer));
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility space-x-* > * + * {
|
||||||
|
margin-left: calc(var(--spacing-base) * --value(integer));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="flex gap-6"></div>
|
||||||
|
<div class="flex space-x-4"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Glassmorphism Utilities
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility glass-* {
|
||||||
|
background: rgba(255, 255, 255, --value(integer) / 100);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility glass-dark-* {
|
||||||
|
background: rgba(0, 0, 0, --value(integer) / 100);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="glass-10"></div>
|
||||||
|
<div class="glass-dark-20"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Utilities with Pseudo-Elements
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility before-content-* {
|
||||||
|
&::before {
|
||||||
|
content: --value([string]);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility after-content-* {
|
||||||
|
&::after {
|
||||||
|
content: --value([string]);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="before:content-['★']">Star before</div>
|
||||||
|
<div class="after:content-['→']">Arrow after</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Custom Utilities Library
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@utility content-auto {
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility content-hidden {
|
||||||
|
content-visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility text-balance {
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility text-pretty {
|
||||||
|
text-wrap: pretty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility truncate-* {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: --value(integer);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility bg-glass {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility text-stroke-* {
|
||||||
|
-webkit-text-stroke-width: --value(integer) px;
|
||||||
|
-webkit-text-stroke-color: --value(--color- *);
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--aspect-square: 1 / 1;
|
||||||
|
--aspect-video: 16 / 9;
|
||||||
|
--aspect-portrait: 3 / 4;
|
||||||
|
--aspect-ultrawide: 21 / 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility aspect-* {
|
||||||
|
aspect-ratio: --value(--aspect- *);
|
||||||
|
aspect-ratio: --value([number]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--tab-size-2: 2;
|
||||||
|
--tab-size-4: 4;
|
||||||
|
--tab-size-8: 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@utility tab-* {
|
||||||
|
tab-size: --value(--tab-size- *);
|
||||||
|
tab-size: --value(integer);
|
||||||
|
tab-size: --value([integer]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why Use @utility Instead of @layer utilities
|
||||||
|
|
||||||
|
**Don't do this:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer utilities {
|
||||||
|
.my-button {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Won't work with variants like `hover:my-button`.
|
||||||
|
|
||||||
|
**Do this:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility my-button {
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Works with all variants: `hover:my-button`, `focus:my-button`, `lg:my-button`.
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use @utility for variant support** - Always use `@utility` instead of `@layer utilities`
|
||||||
|
2. **Support arbitrary values** - Include `--value([type])` for flexibility
|
||||||
|
3. **Use theme variables** - Reference theme with `--value(--namespace- *)`
|
||||||
|
4. **Name utilities semantically** - Use clear, descriptive names
|
||||||
|
5. **Group related utilities** - Keep similar utilities together
|
||||||
|
|
||||||
|
## Common Use Cases
|
||||||
|
|
||||||
|
- Custom CSS properties not in Tailwind
|
||||||
|
- Browser-specific prefixed properties
|
||||||
|
- Complex multi-property patterns
|
||||||
|
- Domain-specific utilities (e.g., print styles)
|
||||||
|
- Experimental CSS features
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- RESEARCH.md section: "Advanced Patterns" → "Custom Utilities with @utility"
|
||||||
262
skills/handling-animations/SKILL.md
Normal file
262
skills/handling-animations/SKILL.md
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
---
|
||||||
|
name: handling-animations
|
||||||
|
description: Define animations with @keyframes within @theme directive, use animate-{name} utilities, and implement entry animations with starting: variant. Use when creating custom animations or entry effects.
|
||||||
|
allowed-tools: Read, Write, Edit, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Handling Animations
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define custom animations using `@keyframes` within the `@theme` directive and use Tailwind's animation utilities with full variant support.
|
||||||
|
|
||||||
|
## Basic Animation Pattern
|
||||||
|
|
||||||
|
Define animations within `@theme`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--animate-fade-in: fade-in 0.3s ease-out;
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-fade-in">Fades in on load</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Animation Variable Naming
|
||||||
|
|
||||||
|
**Pattern:** `--animate-{name}: {animation-shorthand};`
|
||||||
|
|
||||||
|
The variable name determines the utility class:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-spin: spin 1s linear infinite;
|
||||||
|
--animate-bounce: bounce 1s infinite;
|
||||||
|
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Generates utilities:
|
||||||
|
- `animate-spin`
|
||||||
|
- `animate-bounce`
|
||||||
|
- `animate-pulse`
|
||||||
|
|
||||||
|
## Common Animation Types
|
||||||
|
|
||||||
|
### Fade Animations
|
||||||
|
|
||||||
|
**Fade In:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-fade-in: fade-in 0.3s ease-out;
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fade In with Scale:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-fade-in-scale: fade-in-scale 0.3s ease-out;
|
||||||
|
|
||||||
|
@keyframes fade-in-scale {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Slide Animations
|
||||||
|
|
||||||
|
**Slide Up:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-slide-up: slide-up 0.4s ease-out;
|
||||||
|
|
||||||
|
@keyframes slide-up {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For complete directional slide examples (left, right, top, bottom), see [Animation Library](references/animation-library.md#slide-in-from-directions).
|
||||||
|
|
||||||
|
### Motion Animations
|
||||||
|
|
||||||
|
**Spin:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-spin: spin 1s linear infinite;
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bounce:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-bounce: bounce 1s infinite;
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(-25%);
|
||||||
|
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(0);
|
||||||
|
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For additional motion animations (pulse, ping, shake, wiggle), see [Animation Library](references/animation-library.md#complete-animation-examples).
|
||||||
|
|
||||||
|
## Entry Animations with starting:
|
||||||
|
|
||||||
|
The `starting:` variant applies styles before animations begin:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="opacity-100 transition-opacity duration-300 starting:opacity-0">
|
||||||
|
Fades in smoothly
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="
|
||||||
|
translate-y-0 opacity-100
|
||||||
|
transition-all duration-300
|
||||||
|
starting:translate-y-4 starting:opacity-0
|
||||||
|
">
|
||||||
|
Slides up while fading in
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
|
||||||
|
1. Element starts with `starting:` styles
|
||||||
|
2. Browser renders first frame
|
||||||
|
3. Transition/animation begins to final state
|
||||||
|
|
||||||
|
## Animation with Variants
|
||||||
|
|
||||||
|
Animations work with all Tailwind variants:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="hover:animate-spin">Spins on hover</div>
|
||||||
|
<div class="focus:animate-pulse">Pulses on focus</div>
|
||||||
|
<div class="group-hover:animate-bounce">Bounces when parent hovered</div>
|
||||||
|
<div class="lg:animate-fade-in">Animates on large screens</div>
|
||||||
|
<div class="dark:animate-pulse">Pulses in dark mode</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Animation Techniques
|
||||||
|
|
||||||
|
### Staggered Animations
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="animate-slide-up [animation-delay:0s]">Item 1</div>
|
||||||
|
<div class="animate-slide-up [animation-delay:0.1s]">Item 2</div>
|
||||||
|
<div class="animate-slide-up [animation-delay:0.2s]">Item 3</div>
|
||||||
|
<div class="animate-slide-up [animation-delay:0.3s]">Item 4</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Animation Control
|
||||||
|
|
||||||
|
**Delayed Animation:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="
|
||||||
|
animate-fade-in
|
||||||
|
[animation-delay:0.1s]
|
||||||
|
[animation-fill-mode:both]
|
||||||
|
">
|
||||||
|
Delayed fade in
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Pause on Hover:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-spin hover:[animation-play-state:paused]">
|
||||||
|
Pauses on hover
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Define within @theme** - Keep all animations in one place
|
||||||
|
2. **Use semantic names** - `fade-in` not `anim-1`
|
||||||
|
3. **Include timing in variable** - Full animation shorthand
|
||||||
|
4. **Test performance** - Avoid animating expensive properties (width, height)
|
||||||
|
5. **Use transform and opacity** - Hardware accelerated
|
||||||
|
6. **Add will-change sparingly** - Only for known animations
|
||||||
|
7. **Respect prefers-reduced-motion** - Disable animations for accessibility
|
||||||
|
|
||||||
|
## Accessibility
|
||||||
|
|
||||||
|
Respect user motion preferences:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
* {
|
||||||
|
animation-duration: 0.01ms !important;
|
||||||
|
animation-iteration-count: 1 !important;
|
||||||
|
transition-duration: 0.01ms !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
For comprehensive animation examples and patterns, see:
|
||||||
|
|
||||||
|
- [Animation Library](references/animation-library.md) - Complete collection of animation examples
|
||||||
|
- Fade animations (in, out, scale)
|
||||||
|
- Slide animations (all directions)
|
||||||
|
- Motion animations (spin, pulse, ping, bounce)
|
||||||
|
- Complex patterns (shake, wiggle, loading dots)
|
||||||
|
- Complete animation library code
|
||||||
|
- Advanced techniques and performance considerations
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- RESEARCH.md sections: "Entry Animations with starting:" and "Animation Keyframes"
|
||||||
545
skills/handling-animations/references/animation-library.md
Normal file
545
skills/handling-animations/references/animation-library.md
Normal file
@@ -0,0 +1,545 @@
|
|||||||
|
# Animation Library Reference
|
||||||
|
|
||||||
|
This document contains detailed animation examples and complete implementation code for Tailwind CSS v4 animations.
|
||||||
|
|
||||||
|
## Complete Animation Examples
|
||||||
|
|
||||||
|
### Fade In
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-fade-in: fade-in 0.3s ease-out;
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-fade-in">Fades in</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fade In Scale
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-fade-in-scale: fade-in-scale 0.3s ease-out;
|
||||||
|
|
||||||
|
@keyframes fade-in-scale {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-fade-in-scale">Fades and scales in</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Slide In from Bottom
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-slide-up: slide-up 0.4s ease-out;
|
||||||
|
|
||||||
|
@keyframes slide-up {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-slide-up">Slides up while fading in</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spin
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-spin: spin 1s linear infinite;
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-spin">
|
||||||
|
<svg>...</svg>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pulse
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-pulse">Pulsing element</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bounce
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-bounce: bounce 1s infinite;
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(-25%);
|
||||||
|
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(0);
|
||||||
|
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-bounce">Bouncing element</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ping (Ripple Effect)
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||||
|
|
||||||
|
@keyframes ping {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
75%, 100% {
|
||||||
|
transform: scale(2);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="relative">
|
||||||
|
<div class="absolute inset-0 animate-ping bg-blue-500 rounded-full"></div>
|
||||||
|
<div class="relative bg-blue-600 rounded-full w-4 h-4"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complex Animation Patterns
|
||||||
|
|
||||||
|
### Shake Animation
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-shake: shake 0.5s ease-in-out;
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
10%, 30%, 50%, 70%, 90% {
|
||||||
|
transform: translateX(-10px);
|
||||||
|
}
|
||||||
|
20%, 40%, 60%, 80% {
|
||||||
|
transform: translateX(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="hover:animate-shake">Shake on hover</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wiggle
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-wiggle: wiggle 1s ease-in-out infinite;
|
||||||
|
|
||||||
|
@keyframes wiggle {
|
||||||
|
0%, 100% {
|
||||||
|
transform: rotate(-3deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(3deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-wiggle">Wiggling element</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Slide In from Directions
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-slide-in-left: slide-in-left 0.4s ease-out;
|
||||||
|
--animate-slide-in-right: slide-in-right 0.4s ease-out;
|
||||||
|
--animate-slide-in-top: slide-in-top 0.4s ease-out;
|
||||||
|
--animate-slide-in-bottom: slide-in-bottom 0.4s ease-out;
|
||||||
|
|
||||||
|
@keyframes slide-in-left {
|
||||||
|
0% {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-right {
|
||||||
|
0% {
|
||||||
|
transform: translateX(100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-top {
|
||||||
|
0% {
|
||||||
|
transform: translateY(-100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-in-bottom {
|
||||||
|
0% {
|
||||||
|
transform: translateY(100%);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-slide-in-left">Slides from left</div>
|
||||||
|
<div class="animate-slide-in-right">Slides from right</div>
|
||||||
|
<div class="animate-slide-in-top">Slides from top</div>
|
||||||
|
<div class="animate-slide-in-bottom">Slides from bottom</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Loading Dots
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-dot-pulse: dot-pulse 1.4s infinite ease-in-out;
|
||||||
|
|
||||||
|
@keyframes dot-pulse {
|
||||||
|
0%, 80%, 100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
40% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="flex gap-1">
|
||||||
|
<div class="w-2 h-2 bg-blue-500 rounded-full animate-dot-pulse"></div>
|
||||||
|
<div class="w-2 h-2 bg-blue-500 rounded-full animate-dot-pulse [animation-delay:0.2s]"></div>
|
||||||
|
<div class="w-2 h-2 bg-blue-500 rounded-full animate-dot-pulse [animation-delay:0.4s]"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Animation Library
|
||||||
|
|
||||||
|
Full implementation of all animations:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--animate-spin: spin 1s linear infinite;
|
||||||
|
--animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||||
|
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
--animate-bounce: bounce 1s infinite;
|
||||||
|
|
||||||
|
--animate-fade-in: fade-in 0.3s ease-out;
|
||||||
|
--animate-fade-out: fade-out 0.3s ease-in;
|
||||||
|
--animate-fade-in-scale: fade-in-scale 0.3s ease-out;
|
||||||
|
|
||||||
|
--animate-slide-up: slide-up 0.4s ease-out;
|
||||||
|
--animate-slide-down: slide-down 0.4s ease-out;
|
||||||
|
--animate-slide-left: slide-left 0.4s ease-out;
|
||||||
|
--animate-slide-right: slide-right 0.4s ease-out;
|
||||||
|
|
||||||
|
--animate-shake: shake 0.5s ease-in-out;
|
||||||
|
--animate-wiggle: wiggle 1s ease-in-out infinite;
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ping {
|
||||||
|
0% {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
75%, 100% {
|
||||||
|
transform: scale(2);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(-25%);
|
||||||
|
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateY(0);
|
||||||
|
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-out {
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in-scale {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-up {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-down {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-left {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slide-right {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-20px);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
10%, 30%, 50%, 70%, 90% {
|
||||||
|
transform: translateX(-10px);
|
||||||
|
}
|
||||||
|
20%, 40%, 60%, 80% {
|
||||||
|
transform: translateX(10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes wiggle {
|
||||||
|
0%, 100% {
|
||||||
|
transform: rotate(-3deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: rotate(3deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Techniques
|
||||||
|
|
||||||
|
### Animation with Variants
|
||||||
|
|
||||||
|
Animations work with all Tailwind variants:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="hover:animate-spin">Spins on hover</div>
|
||||||
|
<div class="focus:animate-pulse">Pulses on focus</div>
|
||||||
|
<div class="group-hover:animate-bounce">Bounces when parent hovered</div>
|
||||||
|
<div class="lg:animate-fade-in">Animates on large screens</div>
|
||||||
|
<div class="dark:animate-pulse">Pulses in dark mode</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Combining Multiple Animations
|
||||||
|
|
||||||
|
Use arbitrary properties for complex animations:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="
|
||||||
|
animate-fade-in
|
||||||
|
[animation-delay:0.1s]
|
||||||
|
[animation-fill-mode:both]
|
||||||
|
">
|
||||||
|
Delayed fade in
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Staggered Animations
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="animate-slide-up [animation-delay:0s]">Item 1</div>
|
||||||
|
<div class="animate-slide-up [animation-delay:0.1s]">Item 2</div>
|
||||||
|
<div class="animate-slide-up [animation-delay:0.2s]">Item 3</div>
|
||||||
|
<div class="animate-slide-up [animation-delay:0.3s]">Item 4</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pausing Animations
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-spin hover:[animation-play-state:paused]">
|
||||||
|
Pauses on hover
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
1. **Use transform and opacity** - Hardware accelerated properties
|
||||||
|
2. **Avoid animating expensive properties** - Don't animate width, height, or layout properties
|
||||||
|
3. **Add will-change sparingly** - Only for known animations that need performance boost
|
||||||
|
4. **Test on low-end devices** - Ensure smooth performance across all devices
|
||||||
|
5. **Use CSS animations over JavaScript** - Better performance and smoother animations
|
||||||
|
|
||||||
|
## Accessibility
|
||||||
|
|
||||||
|
Respect user motion preferences:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
* {
|
||||||
|
animation-duration: 0.01ms !important;
|
||||||
|
animation-iteration-count: 1 !important;
|
||||||
|
transition-duration: 0.01ms !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
495
skills/migrating-from-v3/SKILL.md
Normal file
495
skills/migrating-from-v3/SKILL.md
Normal file
@@ -0,0 +1,495 @@
|
|||||||
|
---
|
||||||
|
name: migrating-from-v3
|
||||||
|
description: Migrate from Tailwind CSS v3 to v4 including configuration migration (JS to CSS), utility renames, opacity changes, and color system updates. Use when upgrading existing projects to v4.
|
||||||
|
allowed-tools: Read, Write, Edit, Grep, Glob, Bash
|
||||||
|
---
|
||||||
|
|
||||||
|
# Migrating from v3 to v4
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Migrate existing Tailwind CSS v3 projects to v4's CSS-first configuration, updated utilities, and modern color system.
|
||||||
|
|
||||||
|
## Automated Migration Tool
|
||||||
|
|
||||||
|
Tailwind provides an automated upgrade tool:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx @tailwindcss/upgrade@next
|
||||||
|
```
|
||||||
|
|
||||||
|
**Requirements:**
|
||||||
|
- Node.js 20 or higher
|
||||||
|
- Run in a new git branch
|
||||||
|
- Review all changes manually
|
||||||
|
- Test thoroughly
|
||||||
|
|
||||||
|
**What it handles:**
|
||||||
|
- Updates dependencies
|
||||||
|
- Migrates configuration to CSS
|
||||||
|
- Updates template files
|
||||||
|
- Converts utility class names
|
||||||
|
|
||||||
|
**What it doesn't handle:**
|
||||||
|
- Custom plugins (manual migration needed)
|
||||||
|
- Complex configuration logic
|
||||||
|
- Dynamic class generation
|
||||||
|
|
||||||
|
## Configuration Migration
|
||||||
|
|
||||||
|
### JavaScript Config → CSS Theme
|
||||||
|
|
||||||
|
**v3 (tailwind.config.js):**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
content: ['./src/**/*.{html,js}'],
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
brand: '#3b82f6',
|
||||||
|
accent: '#a855f7',
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'sans-serif'],
|
||||||
|
display: ['Satoshi', 'sans-serif'],
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
18: '4.5rem',
|
||||||
|
72: '18rem',
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
'4xl': '2rem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4 (CSS @theme):**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: 'Inter', sans-serif;
|
||||||
|
--font-display: 'Satoshi', sans-serif;
|
||||||
|
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
--color-accent: oklch(0.65 0.25 320);
|
||||||
|
|
||||||
|
--spacing-18: 4.5rem;
|
||||||
|
--spacing-72: 18rem;
|
||||||
|
|
||||||
|
--radius-4xl: 2rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Content Detection
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
content: ['./src/**/*.{html,js,jsx,ts,tsx}']
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
Automatic detection. No configuration needed.
|
||||||
|
|
||||||
|
**Manual control (if needed):**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
@source "../packages/ui";
|
||||||
|
@source not "./legacy";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Import Syntax Changes
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Utility Class Renames
|
||||||
|
|
||||||
|
### Opacity Modifiers
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-black bg-opacity-50"></div>
|
||||||
|
<div class="text-gray-900 text-opacity-75"></div>
|
||||||
|
<div class="border-blue-500 border-opacity-60"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-black/50"></div>
|
||||||
|
<div class="text-gray-900/75"></div>
|
||||||
|
<div class="border-blue-500/60"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Migration pattern:**
|
||||||
|
|
||||||
|
- `bg-opacity-{value}` → `bg-{color}/{value}`
|
||||||
|
- `text-opacity-{value}` → `text-{color}/{value}`
|
||||||
|
- `border-opacity-{value}` → `border-{color}/{value}`
|
||||||
|
|
||||||
|
### Flex Utilities
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="flex-shrink-0"></div>
|
||||||
|
<div class="flex-shrink"></div>
|
||||||
|
<div class="flex-grow-0"></div>
|
||||||
|
<div class="flex-grow"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shrink-0"></div>
|
||||||
|
<div class="shrink"></div>
|
||||||
|
<div class="grow-0"></div>
|
||||||
|
<div class="grow"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Migration pattern:**
|
||||||
|
|
||||||
|
- `flex-shrink-*` → `shrink-*`
|
||||||
|
- `flex-grow-*` → `grow-*`
|
||||||
|
|
||||||
|
### Shadow Utilities
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shadow-sm"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shadow-xs"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Migration:**
|
||||||
|
|
||||||
|
- `shadow-sm` → `shadow-xs`
|
||||||
|
- All other shadow utilities remain the same
|
||||||
|
|
||||||
|
### Ring Width
|
||||||
|
|
||||||
|
**v3 default:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Ring width: 3px
|
||||||
|
|
||||||
|
**v4 default:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Ring width: 1px
|
||||||
|
|
||||||
|
**To keep v3 behavior:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring-3" />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Color System Changes
|
||||||
|
|
||||||
|
### Default Border and Ring Colors
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="border"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Border color: gray-200
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="border"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Border color: currentColor
|
||||||
|
|
||||||
|
**To keep v3 behavior:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="border border-gray-200"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### OkLCh Color Space
|
||||||
|
|
||||||
|
**v3 (RGB):**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
colors: {
|
||||||
|
brand: '#3b82f6',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4 (OkLCh):**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use conversion tool: https://oklch.com/
|
||||||
|
|
||||||
|
## PostCSS Configuration
|
||||||
|
|
||||||
|
### Plugin Changes
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
'tailwindcss': {},
|
||||||
|
'autoprefixer': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
No longer need `autoprefixer` or `postcss-import`.
|
||||||
|
|
||||||
|
### Vite Plugin
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import tailwindcss from 'tailwindcss';
|
||||||
|
import autoprefixer from 'autoprefixer';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
css: {
|
||||||
|
postcss: {
|
||||||
|
plugins: [tailwindcss(), autoprefixer()],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [tailwindcss()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Preflight Changes
|
||||||
|
|
||||||
|
### Placeholder Colors
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
Placeholder text: gray-400
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
Placeholder text: currentColor at 50% opacity
|
||||||
|
|
||||||
|
**To keep v3 behavior:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer base {
|
||||||
|
::placeholder {
|
||||||
|
color: theme('colors.gray.400');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Button Cursor
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
button {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**To restore v3 behavior:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer base {
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Additions
|
||||||
|
|
||||||
|
### Built-in Container Queries
|
||||||
|
|
||||||
|
**v3 (plugin required):**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
plugins: [require('@tailwindcss/container-queries')]
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4 (built-in):**
|
||||||
|
|
||||||
|
No plugin needed. Use `@container` and `@{breakpoint}:` syntax.
|
||||||
|
|
||||||
|
### 3D Transforms
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
Not available
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="transform-3d rotate-x-45 rotate-y-30 translate-z-12"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Starting Variant for Animations
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
Not available
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="opacity-100 starting:opacity-0 transition-opacity"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Breaking Changes Checklist
|
||||||
|
|
||||||
|
- [ ] Update dependencies to v4
|
||||||
|
- [ ] Migrate tailwind.config.js to @theme
|
||||||
|
- [ ] Replace @tailwind directives with @import
|
||||||
|
- [ ] Update PostCSS configuration
|
||||||
|
- [ ] Convert opacity utilities (bg-opacity → bg-{color}/{value})
|
||||||
|
- [ ] Rename flex utilities (flex-shrink → shrink)
|
||||||
|
- [ ] Update shadow-sm to shadow-xs
|
||||||
|
- [ ] Add explicit border colors if using bare `border`
|
||||||
|
- [ ] Update ring-3 if expecting 3px default
|
||||||
|
- [ ] Convert hex colors to oklch()
|
||||||
|
- [ ] Remove container-queries plugin (now built-in)
|
||||||
|
- [ ] Test placeholder colors
|
||||||
|
- [ ] Test button cursor behavior
|
||||||
|
- [ ] Update arbitrary value syntax (spaces → underscores)
|
||||||
|
|
||||||
|
## Migration Strategy
|
||||||
|
|
||||||
|
### Phase 1: Preparation
|
||||||
|
|
||||||
|
1. Create new git branch
|
||||||
|
2. Ensure all changes committed
|
||||||
|
3. Run automated migration tool
|
||||||
|
4. Review generated changes
|
||||||
|
|
||||||
|
### Phase 2: Configuration
|
||||||
|
|
||||||
|
1. Convert tailwind.config.js to CSS @theme
|
||||||
|
2. Update PostCSS/Vite configuration
|
||||||
|
3. Replace @tailwind directives
|
||||||
|
4. Add @source if needed
|
||||||
|
|
||||||
|
### Phase 3: Utilities
|
||||||
|
|
||||||
|
1. Search and replace opacity modifiers
|
||||||
|
2. Rename flex utilities
|
||||||
|
3. Update shadow utilities
|
||||||
|
4. Add explicit border colors
|
||||||
|
5. Convert hex colors to oklch()
|
||||||
|
|
||||||
|
### Phase 4: Testing
|
||||||
|
|
||||||
|
1. Test all pages/components
|
||||||
|
2. Verify responsive behavior
|
||||||
|
3. Check dark mode
|
||||||
|
4. Test interactive states
|
||||||
|
5. Validate production build
|
||||||
|
|
||||||
|
### Phase 5: Cleanup
|
||||||
|
|
||||||
|
1. Remove unused dependencies
|
||||||
|
2. Delete tailwind.config.js
|
||||||
|
3. Update documentation
|
||||||
|
4. Commit changes
|
||||||
|
|
||||||
|
## Common Issues
|
||||||
|
|
||||||
|
### Styles Not Applying
|
||||||
|
|
||||||
|
Check:
|
||||||
|
1. CSS import: `@import "tailwindcss";`
|
||||||
|
2. PostCSS plugin: `@tailwindcss/postcss`
|
||||||
|
3. Vite plugin: `@tailwindcss/vite`
|
||||||
|
4. Template files not in .gitignore
|
||||||
|
|
||||||
|
### Class Names Not Working
|
||||||
|
|
||||||
|
Ensure:
|
||||||
|
1. Class names are complete strings
|
||||||
|
2. Not using dynamic concatenation
|
||||||
|
3. Using underscores for spaces in arbitrary values
|
||||||
|
|
||||||
|
### Colors Look Different
|
||||||
|
|
||||||
|
OkLCh uses different color space. Convert hex to oklch using:
|
||||||
|
https://oklch.com/
|
||||||
|
|
||||||
|
### Build Errors
|
||||||
|
|
||||||
|
Check:
|
||||||
|
1. Node.js version (20+)
|
||||||
|
2. Dependencies updated
|
||||||
|
3. PostCSS config using correct plugin
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- references/breaking-changes.md - Complete breaking changes list
|
||||||
|
- references/migration-checklist.md - Step-by-step migration guide
|
||||||
516
skills/migrating-from-v3/references/breaking-changes.md
Normal file
516
skills/migrating-from-v3/references/breaking-changes.md
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
# Complete Breaking Changes List
|
||||||
|
|
||||||
|
## Configuration System
|
||||||
|
|
||||||
|
### JavaScript → CSS Configuration
|
||||||
|
|
||||||
|
**Breaking:** No more `tailwind.config.js` file.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: { brand: '#3b82f6' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** All theme customization moves to CSS.
|
||||||
|
|
||||||
|
### Content Detection
|
||||||
|
|
||||||
|
**Breaking:** No manual content array needed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
content: ['./src/**/*.{html,js}']
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
Automatic detection. Manual control via `@source` if needed.
|
||||||
|
|
||||||
|
**Impact:** Simplified setup, but less explicit control.
|
||||||
|
|
||||||
|
## Import Directives
|
||||||
|
|
||||||
|
### @tailwind → @import
|
||||||
|
|
||||||
|
**Breaking:** Different import syntax.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** All templates need updating.
|
||||||
|
|
||||||
|
## Utility Class Changes
|
||||||
|
|
||||||
|
### Opacity Modifiers Removed
|
||||||
|
|
||||||
|
**Breaking:** Separate opacity utilities removed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-black bg-opacity-50"></div>
|
||||||
|
<div class="text-gray-900 text-opacity-75"></div>
|
||||||
|
<div class="border-blue-500 border-opacity-60"></div>
|
||||||
|
<div class="ring-blue-500 ring-opacity-30"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-black/50"></div>
|
||||||
|
<div class="text-gray-900/75"></div>
|
||||||
|
<div class="border-blue-500/60"></div>
|
||||||
|
<div class="ring-blue-500/30"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Search and replace needed across entire codebase.
|
||||||
|
|
||||||
|
**Automated fix:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -name "*.html" -o -name "*.jsx" -o -name "*.tsx" | xargs sed -i '' 's/bg-\([a-z-]*\) bg-opacity-\([0-9]*\)/bg-\1\/\2/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flex Utility Renames
|
||||||
|
|
||||||
|
**Breaking:** Utility names changed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="flex-shrink-0"></div>
|
||||||
|
<div class="flex-shrink"></div>
|
||||||
|
<div class="flex-grow-0"></div>
|
||||||
|
<div class="flex-grow"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shrink-0"></div>
|
||||||
|
<div class="shrink"></div>
|
||||||
|
<div class="grow-0"></div>
|
||||||
|
<div class="grow"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** All flex utilities need renaming.
|
||||||
|
|
||||||
|
### Shadow Utility Rename
|
||||||
|
|
||||||
|
**Breaking:** Smallest shadow renamed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shadow-sm"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shadow-xs"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Update all uses of `shadow-sm`.
|
||||||
|
|
||||||
|
### Ring Default Width
|
||||||
|
|
||||||
|
**Breaking:** Default ring width changed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Ring width: 3px
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Ring width: 1px
|
||||||
|
|
||||||
|
**Fix for v3 behavior:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring-3" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** All bare `ring` utilities render thinner.
|
||||||
|
|
||||||
|
## Color System
|
||||||
|
|
||||||
|
### Default Border Color
|
||||||
|
|
||||||
|
**Breaking:** Border color changed from gray to currentColor.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="border"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Border color: gray-200
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="border"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Border color: currentColor (inherits text color)
|
||||||
|
|
||||||
|
**Fix for v3 behavior:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="border border-gray-200"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Borders may appear different colors.
|
||||||
|
|
||||||
|
### Default Ring Color
|
||||||
|
|
||||||
|
**Breaking:** Ring color changed from blue to currentColor.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Ring color: blue-500
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring" />
|
||||||
|
```
|
||||||
|
|
||||||
|
Ring color: currentColor
|
||||||
|
|
||||||
|
**Fix for v3 behavior:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring ring-blue-500" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Rings inherit text color.
|
||||||
|
|
||||||
|
### OkLCh Color Space
|
||||||
|
|
||||||
|
**Breaking:** Color values use OkLCh instead of RGB.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
colors: {
|
||||||
|
brand: '#3b82f6',
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Custom colors need conversion. Colors may look slightly different (more vivid on modern displays).
|
||||||
|
|
||||||
|
## PostCSS Changes
|
||||||
|
|
||||||
|
### Plugin Name
|
||||||
|
|
||||||
|
**Breaking:** Different PostCSS plugin.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
plugins: {
|
||||||
|
'tailwindcss': {},
|
||||||
|
'autoprefixer': {},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** PostCSS config needs updating. Remove `autoprefixer` and `postcss-import` (no longer needed).
|
||||||
|
|
||||||
|
## Preflight Changes
|
||||||
|
|
||||||
|
### Placeholder Color
|
||||||
|
|
||||||
|
**Breaking:** Placeholder text color changed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
::placeholder {
|
||||||
|
color: theme('colors.gray.400');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
::placeholder {
|
||||||
|
color: currentColor;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Placeholders inherit text color at 50% opacity.
|
||||||
|
|
||||||
|
**Fix for v3 behavior:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer base {
|
||||||
|
::placeholder {
|
||||||
|
color: theme('colors.gray.400');
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Button Cursor
|
||||||
|
|
||||||
|
**Breaking:** Button cursor changed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
button {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Buttons no longer show pointer cursor by default.
|
||||||
|
|
||||||
|
**Fix for v3 behavior:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer base {
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Or add explicit classes:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button class="cursor-pointer">Click me</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Arbitrary Values
|
||||||
|
|
||||||
|
### Space Handling
|
||||||
|
|
||||||
|
**Breaking:** Spaces in arbitrary values use underscores.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="grid-cols-[1fr,500px,2fr]"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="grid-cols-[1fr_500px_2fr]"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** All arbitrary values with commas need updating.
|
||||||
|
|
||||||
|
## Browser Support
|
||||||
|
|
||||||
|
### Minimum Versions
|
||||||
|
|
||||||
|
**Breaking:** Dropped support for older browsers.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
- IE 11+
|
||||||
|
- Safari 10+
|
||||||
|
- Chrome 60+
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
- Safari 16.4+
|
||||||
|
- Chrome 111+
|
||||||
|
- Firefox 128+
|
||||||
|
|
||||||
|
**Impact:** Projects requiring older browser support cannot upgrade.
|
||||||
|
|
||||||
|
## CSS Preprocessors
|
||||||
|
|
||||||
|
### No Sass/Less/Stylus Support
|
||||||
|
|
||||||
|
**Breaking:** Incompatible with CSS preprocessors.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
Can use with Sass, Less, Stylus
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
Cannot use CSS preprocessors (Tailwind functions as preprocessing layer)
|
||||||
|
|
||||||
|
**Impact:** Remove CSS preprocessors from build pipeline.
|
||||||
|
|
||||||
|
## Plugin System
|
||||||
|
|
||||||
|
### Plugin API Changes
|
||||||
|
|
||||||
|
**Breaking:** Plugin API completely rewritten.
|
||||||
|
|
||||||
|
**v3 plugin:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const plugin = require('tailwindcss/plugin');
|
||||||
|
|
||||||
|
module.exports = plugin(function ({ addUtilities, theme }) {
|
||||||
|
addUtilities({
|
||||||
|
'.content-auto': {
|
||||||
|
'content-visibility': 'auto',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4 equivalent:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility content-auto {
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** All custom plugins need manual rewrite.
|
||||||
|
|
||||||
|
## @apply Restrictions
|
||||||
|
|
||||||
|
### Limited @apply Support
|
||||||
|
|
||||||
|
**Breaking:** @apply only works for small subset of utilities.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
.btn {
|
||||||
|
@apply px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
@apply has limited support. Use @utility instead:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility btn {
|
||||||
|
padding: var(--spacing-2) var(--spacing-4);
|
||||||
|
background: var(--color-blue-600);
|
||||||
|
color: var(--color-white);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Impact:** Many @apply patterns need refactoring.
|
||||||
|
|
||||||
|
## Mobile Hover Behavior
|
||||||
|
|
||||||
|
### Hover on Touch Devices
|
||||||
|
|
||||||
|
**Breaking:** Hover styles don't apply on touch devices.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
Hover styles triggered on tap
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
Hover styles only on devices supporting hover
|
||||||
|
|
||||||
|
**Impact:** Touch devices won't show hover states (improves UX).
|
||||||
|
|
||||||
|
## Container Plugin
|
||||||
|
|
||||||
|
### Built-in Container Queries
|
||||||
|
|
||||||
|
**Breaking:** Container queries plugin no longer needed.
|
||||||
|
|
||||||
|
**v3:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
plugins: [require('@tailwindcss/container-queries')]
|
||||||
|
```
|
||||||
|
|
||||||
|
**v4:**
|
||||||
|
|
||||||
|
Built-in. No plugin needed.
|
||||||
|
|
||||||
|
**Impact:** Remove plugin dependency. Syntax remains same.
|
||||||
|
|
||||||
|
## Summary Table
|
||||||
|
|
||||||
|
| Change | v3 | v4 | Impact |
|
||||||
|
|--------|----|----|--------|
|
||||||
|
| Config | tailwind.config.js | @theme | High |
|
||||||
|
| Import | @tailwind | @import | High |
|
||||||
|
| Opacity | bg-opacity-50 | bg-{color}/50 | High |
|
||||||
|
| Flex | flex-shrink | shrink | Medium |
|
||||||
|
| Shadow | shadow-sm | shadow-xs | Low |
|
||||||
|
| Ring width | 3px | 1px | Medium |
|
||||||
|
| Border color | gray-200 | currentColor | Medium |
|
||||||
|
| Color space | RGB | OkLCh | Medium |
|
||||||
|
| PostCSS | tailwindcss | @tailwindcss/postcss | High |
|
||||||
|
| Placeholder | gray-400 | currentColor/50 | Low |
|
||||||
|
| Button cursor | pointer | default | Low |
|
||||||
|
| Browsers | IE 11+ | Safari 16.4+ | High |
|
||||||
|
| Preprocessors | Supported | Not supported | High |
|
||||||
|
| Plugins | JS API | CSS @utility | High |
|
||||||
469
skills/migrating-from-v3/references/migration-checklist.md
Normal file
469
skills/migrating-from-v3/references/migration-checklist.md
Normal file
@@ -0,0 +1,469 @@
|
|||||||
|
# Step-by-Step Migration Checklist
|
||||||
|
|
||||||
|
## Pre-Migration
|
||||||
|
|
||||||
|
- [ ] Create new git branch: `git checkout -b upgrade-tailwind-v4`
|
||||||
|
- [ ] Commit all current changes
|
||||||
|
- [ ] Document current Tailwind version
|
||||||
|
- [ ] Backup tailwind.config.js
|
||||||
|
- [ ] Review custom plugins in use
|
||||||
|
- [ ] Check browser support requirements
|
||||||
|
- [ ] Note any CSS preprocessor usage
|
||||||
|
|
||||||
|
## Phase 1: Dependencies
|
||||||
|
|
||||||
|
### Update Package Dependencies
|
||||||
|
|
||||||
|
- [ ] Update Tailwind CSS to v4
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install tailwindcss@next
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Install appropriate build tool plugin
|
||||||
|
|
||||||
|
**For Vite:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @tailwindcss/vite
|
||||||
|
```
|
||||||
|
|
||||||
|
**For PostCSS:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @tailwindcss/postcss
|
||||||
|
```
|
||||||
|
|
||||||
|
**For CLI:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @tailwindcss/cli
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Remove deprecated dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm uninstall autoprefixer postcss-import @tailwindcss/container-queries
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Update package.json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"tailwindcss": "^4.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/vite": "^4.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 2: Build Configuration
|
||||||
|
|
||||||
|
### Vite Configuration
|
||||||
|
|
||||||
|
- [ ] Update vite.config.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react(), tailwindcss()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Remove PostCSS config if using Vite plugin
|
||||||
|
- [ ] Test build: `npm run build`
|
||||||
|
|
||||||
|
### PostCSS Configuration
|
||||||
|
|
||||||
|
- [ ] Update postcss.config.js
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Remove autoprefixer and postcss-import
|
||||||
|
- [ ] Test build: `npm run build`
|
||||||
|
|
||||||
|
### Next.js Configuration
|
||||||
|
|
||||||
|
- [ ] Ensure postcss.config.js exists
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Test: `npm run dev`
|
||||||
|
|
||||||
|
## Phase 3: CSS Configuration
|
||||||
|
|
||||||
|
### Migrate tailwind.config.js to @theme
|
||||||
|
|
||||||
|
- [ ] Open tailwind.config.js
|
||||||
|
- [ ] Open main CSS file (e.g., src/index.css)
|
||||||
|
- [ ] Replace @tailwind directives
|
||||||
|
|
||||||
|
**Old:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
```
|
||||||
|
|
||||||
|
**New:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Convert theme.extend to @theme
|
||||||
|
|
||||||
|
**Example conversion:**
|
||||||
|
|
||||||
|
**tailwind.config.js:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
brand: '#3b82f6',
|
||||||
|
accent: '#a855f7',
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
sans: ['Inter', 'sans-serif'],
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
18: '4.5rem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**CSS:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: 'Inter', sans-serif;
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
--color-accent: oklch(0.65 0.25 320);
|
||||||
|
--spacing-18: 4.5rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Convert hex colors to oklch() using https://oklch.com/
|
||||||
|
- [ ] Test: colors render correctly
|
||||||
|
|
||||||
|
### Content Detection
|
||||||
|
|
||||||
|
- [ ] Remove content array (automatic detection)
|
||||||
|
- [ ] Add @source directives if needed
|
||||||
|
|
||||||
|
```css
|
||||||
|
@source "../packages/ui";
|
||||||
|
@source not "./legacy";
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Verify all template files are detected
|
||||||
|
- [ ] Check .gitignore excludes node_modules
|
||||||
|
|
||||||
|
### Custom CSS
|
||||||
|
|
||||||
|
- [ ] Migrate @layer components to CSS
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer components {
|
||||||
|
.btn {
|
||||||
|
padding: var(--spacing-2) var(--spacing-4);
|
||||||
|
background: var(--color-blue-600);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Convert @layer utilities to @utility
|
||||||
|
|
||||||
|
**Old:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer utilities {
|
||||||
|
.content-auto {
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**New:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility content-auto {
|
||||||
|
content-visibility: auto;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 4: Utility Class Updates
|
||||||
|
|
||||||
|
### Opacity Modifiers
|
||||||
|
|
||||||
|
- [ ] Search for opacity utilities
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -r "bg-opacity-" src/
|
||||||
|
grep -r "text-opacity-" src/
|
||||||
|
grep -r "border-opacity-" src/
|
||||||
|
grep -r "ring-opacity-" src/
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Replace with slash syntax
|
||||||
|
|
||||||
|
**Find and replace:**
|
||||||
|
|
||||||
|
- `bg-{color} bg-opacity-{value}` → `bg-{color}/{value}`
|
||||||
|
- `text-{color} text-opacity-{value}` → `text-{color}/{value}`
|
||||||
|
- `border-{color} border-opacity-{value}` → `border-{color}/{value}`
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-black bg-opacity-50"></div>
|
||||||
|
→
|
||||||
|
<div class="bg-black/50"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Test: opacity values render correctly
|
||||||
|
|
||||||
|
### Flex Utilities
|
||||||
|
|
||||||
|
- [ ] Search for flex utilities
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -r "flex-shrink" src/
|
||||||
|
grep -r "flex-grow" src/
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Replace with new names
|
||||||
|
|
||||||
|
**Find and replace:**
|
||||||
|
|
||||||
|
- `flex-shrink-0` → `shrink-0`
|
||||||
|
- `flex-shrink` → `shrink`
|
||||||
|
- `flex-grow-0` → `grow-0`
|
||||||
|
- `flex-grow` → `grow`
|
||||||
|
|
||||||
|
### Shadow Utilities
|
||||||
|
|
||||||
|
- [ ] Search for shadow-sm
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -r "shadow-sm" src/
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Replace with shadow-xs
|
||||||
|
|
||||||
|
```
|
||||||
|
shadow-sm → shadow-xs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ring Utilities
|
||||||
|
|
||||||
|
- [ ] Search for bare `ring` class
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -r 'class="[^"]*ring[^-"]' src/
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Add explicit width if expecting 3px default
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input class="ring" />
|
||||||
|
→
|
||||||
|
<input class="ring-3" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Border Utilities
|
||||||
|
|
||||||
|
- [ ] Search for bare `border` class
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -r 'class="[^"]*border[^-"]' src/
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Add explicit color if expecting gray
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="border"></div>
|
||||||
|
→
|
||||||
|
<div class="border border-gray-200"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 5: Arbitrary Values
|
||||||
|
|
||||||
|
### Space Handling
|
||||||
|
|
||||||
|
- [ ] Search for arbitrary values with commas
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -r "grid-cols-\[.*,.*\]" src/
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] Replace commas with underscores
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="grid-cols-[1fr,500px,2fr]"></div>
|
||||||
|
→
|
||||||
|
<div class="grid-cols-[1fr_500px_2fr]"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Phase 6: Testing
|
||||||
|
|
||||||
|
### Build Tests
|
||||||
|
|
||||||
|
- [ ] Run development build: `npm run dev`
|
||||||
|
- [ ] Check console for errors
|
||||||
|
- [ ] Verify styles load
|
||||||
|
- [ ] Run production build: `npm run build`
|
||||||
|
- [ ] Check build output
|
||||||
|
- [ ] Test production bundle
|
||||||
|
|
||||||
|
### Visual Testing
|
||||||
|
|
||||||
|
- [ ] Test home page
|
||||||
|
- [ ] Test all major pages
|
||||||
|
- [ ] Check responsive breakpoints
|
||||||
|
- [ ] Verify dark mode (if used)
|
||||||
|
- [ ] Test hover states
|
||||||
|
- [ ] Test focus states
|
||||||
|
- [ ] Check form inputs
|
||||||
|
- [ ] Verify buttons
|
||||||
|
- [ ] Check modals/overlays
|
||||||
|
- [ ] Test animations
|
||||||
|
|
||||||
|
### Component Testing
|
||||||
|
|
||||||
|
- [ ] Test each component in isolation
|
||||||
|
- [ ] Verify colors match
|
||||||
|
- [ ] Check spacing
|
||||||
|
- [ ] Test typography
|
||||||
|
- [ ] Verify shadows and borders
|
||||||
|
- [ ] Check opacity values
|
||||||
|
|
||||||
|
### Browser Testing
|
||||||
|
|
||||||
|
- [ ] Safari 16.4+
|
||||||
|
- [ ] Chrome 111+
|
||||||
|
- [ ] Firefox 128+
|
||||||
|
- [ ] Mobile Safari
|
||||||
|
- [ ] Mobile Chrome
|
||||||
|
|
||||||
|
## Phase 7: Cleanup
|
||||||
|
|
||||||
|
### Remove Old Files
|
||||||
|
|
||||||
|
- [ ] Delete tailwind.config.js
|
||||||
|
- [ ] Remove old PostCSS config (if using Vite plugin)
|
||||||
|
- [ ] Clean node_modules
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf node_modules package-lock.json
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Documentation
|
||||||
|
|
||||||
|
- [ ] Update README.md
|
||||||
|
- [ ] Document new setup process
|
||||||
|
- [ ] Update contribution guide
|
||||||
|
- [ ] Note new browser requirements
|
||||||
|
|
||||||
|
### Code Review
|
||||||
|
|
||||||
|
- [ ] Review all changed files
|
||||||
|
- [ ] Check for missed migrations
|
||||||
|
- [ ] Verify no broken styles
|
||||||
|
- [ ] Run linter: `npm run lint`
|
||||||
|
- [ ] Run tests: `npm test`
|
||||||
|
|
||||||
|
## Phase 8: Deploy
|
||||||
|
|
||||||
|
### Pre-Deploy Checks
|
||||||
|
|
||||||
|
- [ ] All tests passing
|
||||||
|
- [ ] No console errors
|
||||||
|
- [ ] Production build successful
|
||||||
|
- [ ] Visual regression tests pass
|
||||||
|
- [ ] Performance metrics acceptable
|
||||||
|
|
||||||
|
### Deploy
|
||||||
|
|
||||||
|
- [ ] Merge PR to main
|
||||||
|
- [ ] Deploy to staging
|
||||||
|
- [ ] Test staging environment
|
||||||
|
- [ ] Deploy to production
|
||||||
|
- [ ] Monitor for issues
|
||||||
|
|
||||||
|
### Post-Deploy
|
||||||
|
|
||||||
|
- [ ] Verify production site
|
||||||
|
- [ ] Check analytics for errors
|
||||||
|
- [ ] Monitor performance
|
||||||
|
- [ ] Gather feedback
|
||||||
|
|
||||||
|
## Common Issues Checklist
|
||||||
|
|
||||||
|
- [ ] Styles not applying → Check @import syntax
|
||||||
|
- [ ] Build errors → Verify PostCSS/Vite config
|
||||||
|
- [ ] Colors different → Convert hex to oklch
|
||||||
|
- [ ] Borders wrong color → Add explicit border color
|
||||||
|
- [ ] Placeholders wrong → Check preflight changes
|
||||||
|
- [ ] Buttons wrong cursor → Add cursor-pointer
|
||||||
|
- [ ] Missing utilities → Check for typos
|
||||||
|
- [ ] Dark mode broken → Verify class strategy
|
||||||
|
|
||||||
|
## Rollback Plan
|
||||||
|
|
||||||
|
If migration fails:
|
||||||
|
|
||||||
|
- [ ] Revert git branch: `git checkout main`
|
||||||
|
- [ ] Delete branch: `git branch -D upgrade-tailwind-v4`
|
||||||
|
- [ ] Reinstall dependencies: `npm install`
|
||||||
|
- [ ] Document issues encountered
|
||||||
|
- [ ] Plan remediation
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- [ ] All pages render correctly
|
||||||
|
- [ ] No console errors
|
||||||
|
- [ ] Production build successful
|
||||||
|
- [ ] All tests passing
|
||||||
|
- [ ] Performance maintained or improved
|
||||||
|
- [ ] No visual regressions
|
||||||
|
- [ ] Browser support verified
|
||||||
|
- [ ] Documentation updated
|
||||||
|
|
||||||
|
## Estimated Timeline
|
||||||
|
|
||||||
|
- Pre-migration: 1 hour
|
||||||
|
- Dependencies & build config: 1-2 hours
|
||||||
|
- CSS migration: 2-4 hours
|
||||||
|
- Utility updates: 4-8 hours
|
||||||
|
- Testing: 4-8 hours
|
||||||
|
- Cleanup & documentation: 1-2 hours
|
||||||
|
- Deploy: 1-2 hours
|
||||||
|
|
||||||
|
**Total: 14-27 hours** depending on project size
|
||||||
372
skills/reviewing-tailwind-patterns/SKILL.md
Normal file
372
skills/reviewing-tailwind-patterns/SKILL.md
Normal file
@@ -0,0 +1,372 @@
|
|||||||
|
---
|
||||||
|
name: reviewing-tailwind-patterns
|
||||||
|
description: Review Tailwind CSS v4 patterns for configuration, theming, and utility usage. Use when reviewing CSS files, Vite configs, or components using Tailwind.
|
||||||
|
review: true
|
||||||
|
allowed-tools: Read, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Reviewing Tailwind v4 Patterns
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Review Tailwind CSS v4 implementations for correct configuration, modern patterns, and best practices.
|
||||||
|
|
||||||
|
## Review Checklist
|
||||||
|
|
||||||
|
### Configuration Review
|
||||||
|
|
||||||
|
**Check build tool configuration:**
|
||||||
|
|
||||||
|
- [ ] Using `@tailwindcss/vite` for Vite projects (preferred over PostCSS)
|
||||||
|
- [ ] Using `@tailwindcss/postcss` for other build tools
|
||||||
|
- [ ] No `tailwind.config.js` file (v4 uses CSS configuration)
|
||||||
|
- [ ] PostCSS config uses correct plugin name (`@tailwindcss/postcss`)
|
||||||
|
- [ ] Not using deprecated plugins (autoprefixer, postcss-import)
|
||||||
|
|
||||||
|
**Vite config pattern:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react(), tailwindcss()],
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**PostCSS config pattern:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
'@tailwindcss/postcss': {},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### CSS File Review
|
||||||
|
|
||||||
|
**Check import syntax:**
|
||||||
|
|
||||||
|
- [ ] Using `@import 'tailwindcss';` (not @tailwind directives)
|
||||||
|
- [ ] @theme directive present for customization
|
||||||
|
- [ ] Theme variables use correct namespaces
|
||||||
|
- [ ] Colors use oklch() format (not hex or rgb)
|
||||||
|
- [ ] @keyframes defined within @theme (not outside)
|
||||||
|
|
||||||
|
**Correct pattern:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: 'Inter', sans-serif;
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--spacing-18: 4.5rem;
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Anti-patterns:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@tailwind base;
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--color-primary: #3b82f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Theme Variables Review
|
||||||
|
|
||||||
|
**Check namespace usage:**
|
||||||
|
|
||||||
|
- [ ] Color variables use `--color-*` prefix
|
||||||
|
- [ ] Font families use `--font-*` prefix
|
||||||
|
- [ ] Spacing uses `--spacing-*` prefix
|
||||||
|
- [ ] Border radius uses `--radius-*` prefix
|
||||||
|
- [ ] Animations use `--animate-*` prefix
|
||||||
|
- [ ] Semantic naming over generic scales
|
||||||
|
|
||||||
|
**Good pattern:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-secondary: oklch(0.75 0.22 320);
|
||||||
|
--color-success: oklch(0.72 0.15 142);
|
||||||
|
--color-error: oklch(0.65 0.22 25);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Anti-pattern:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--primary: oklch(0.65 0.25 270);
|
||||||
|
--blue: oklch(0.75 0.22 320);
|
||||||
|
--my-color: oklch(0.72 0.15 142);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Color Format Review
|
||||||
|
|
||||||
|
**Check color definitions:**
|
||||||
|
|
||||||
|
- [ ] Using oklch() format (not hex, rgb, or hsl)
|
||||||
|
- [ ] Lightness between 0-1
|
||||||
|
- [ ] Chroma between 0-0.4
|
||||||
|
- [ ] Hue between 0-360
|
||||||
|
|
||||||
|
**Correct:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
```
|
||||||
|
|
||||||
|
**Incorrect:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
--color-brand: #3b82f6;
|
||||||
|
--color-accent: rgb(168, 85, 247);
|
||||||
|
--color-success: hsl(142, 76%, 36%);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Utility Usage Review
|
||||||
|
|
||||||
|
**Check for v3 patterns:**
|
||||||
|
|
||||||
|
- [ ] No `bg-opacity-*` utilities (use `bg-{color}/{opacity}`)
|
||||||
|
- [ ] No `flex-shrink-*` (use `shrink-*`)
|
||||||
|
- [ ] No `flex-grow-*` (use `grow-*`)
|
||||||
|
- [ ] No `shadow-sm` (use `shadow-xs`)
|
||||||
|
- [ ] Explicit border colors (not bare `border`)
|
||||||
|
- [ ] Explicit ring widths if expecting 3px (use `ring-3`)
|
||||||
|
|
||||||
|
**v4 patterns:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-black/50"></div>
|
||||||
|
<div class="shrink-0 grow"></div>
|
||||||
|
<div class="shadow-xs"></div>
|
||||||
|
<div class="border border-gray-200"></div>
|
||||||
|
<input class="ring-3 ring-blue-500" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**v3 anti-patterns:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-black bg-opacity-50"></div>
|
||||||
|
<div class="flex-shrink-0 flex-grow"></div>
|
||||||
|
<div class="shadow-sm"></div>
|
||||||
|
<div class="border"></div>
|
||||||
|
<input class="ring" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container Query Review
|
||||||
|
|
||||||
|
**Check container query usage:**
|
||||||
|
|
||||||
|
- [ ] Parent has `@container` or `@container/{name}`
|
||||||
|
- [ ] Container breakpoints use `@` prefix
|
||||||
|
- [ ] Named containers use consistent naming
|
||||||
|
- [ ] Mixing container and viewport queries correctly
|
||||||
|
|
||||||
|
**Correct pattern:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container/main">
|
||||||
|
<div class="grid-cols-1 @md/main:grid-cols-2 @lg/main:grid-cols-3"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Anti-pattern:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div>
|
||||||
|
<div class="grid-cols-1 @md:grid-cols-2"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Utility Review
|
||||||
|
|
||||||
|
**Check @utility usage:**
|
||||||
|
|
||||||
|
- [ ] Using `@utility` (not `@layer utilities`)
|
||||||
|
- [ ] Using `--value()` functions correctly
|
||||||
|
- [ ] Supporting arbitrary values when appropriate
|
||||||
|
- [ ] Providing variant support
|
||||||
|
|
||||||
|
**Correct pattern:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@utility tab-* {
|
||||||
|
tab-size: --value(--tab-size- *);
|
||||||
|
tab-size: --value(integer);
|
||||||
|
tab-size: --value([integer]);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Anti-pattern:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@layer utilities {
|
||||||
|
.tab-4 {
|
||||||
|
tab-size: 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Animation Review
|
||||||
|
|
||||||
|
**Check animation patterns:**
|
||||||
|
|
||||||
|
- [ ] @keyframes defined within @theme
|
||||||
|
- [ ] Animation variables use `--animate-*` prefix
|
||||||
|
- [ ] Animation shorthand includes timing
|
||||||
|
- [ ] Using `starting:` variant for entry animations
|
||||||
|
|
||||||
|
**Correct pattern:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-fade-in: fade-in 0.3s ease-out;
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Anti-pattern:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--animate-fade-in: fade-in;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Component Pattern Review
|
||||||
|
|
||||||
|
**Check component reusability:**
|
||||||
|
|
||||||
|
- [ ] Components use container queries for portability
|
||||||
|
- [ ] Semantic color names (not numbered scales)
|
||||||
|
- [ ] Responsive utilities applied appropriately
|
||||||
|
- [ ] Dark mode variants when needed
|
||||||
|
|
||||||
|
**Good pattern:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<article class="bg-white dark:bg-gray-900 rounded-lg p-4 @md:p-6">
|
||||||
|
<h2 class="text-lg @md:text-xl font-bold text-primary">Title</h2>
|
||||||
|
<p class="text-sm @md:text-base text-gray-600 dark:text-gray-300">Content</p>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Source Detection Review
|
||||||
|
|
||||||
|
**Check content detection:**
|
||||||
|
|
||||||
|
- [ ] No manual content array (automatic detection)
|
||||||
|
- [ ] Using `@source` only when needed
|
||||||
|
- [ ] Excluding unnecessary directories with `@source not`
|
||||||
|
- [ ] node_modules in .gitignore
|
||||||
|
|
||||||
|
**When to use @source:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@source "../packages/ui";
|
||||||
|
@source not "./legacy";
|
||||||
|
```
|
||||||
|
|
||||||
|
**Don't do this:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss' source(none);
|
||||||
|
@source "./src/**/*.{html,js,jsx,ts,tsx}";
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Issues to Flag
|
||||||
|
|
||||||
|
### High Priority
|
||||||
|
|
||||||
|
1. **Using v3 syntax** - Opacity utilities, flex utilities
|
||||||
|
2. **Wrong import syntax** - `@tailwind` instead of `@import`
|
||||||
|
3. **Hex colors in theme** - Should use oklch()
|
||||||
|
4. **Wrong PostCSS plugin** - Should be `@tailwindcss/postcss`
|
||||||
|
5. **Missing @container** - Container queries without parent
|
||||||
|
|
||||||
|
### Medium Priority
|
||||||
|
|
||||||
|
1. **Non-semantic color names** - Using numbered scales
|
||||||
|
2. **Bare border/ring classes** - May render unexpectedly
|
||||||
|
3. **@keyframes outside @theme** - Won't generate utilities
|
||||||
|
4. **Wrong namespace prefixes** - Won't generate correct utilities
|
||||||
|
5. **Using @layer utilities** - Should use @utility
|
||||||
|
|
||||||
|
### Low Priority
|
||||||
|
|
||||||
|
1. **No dark mode variants** - May be intentional
|
||||||
|
2. **Mixing viewport and container queries** - May be correct
|
||||||
|
3. **Arbitrary values** - Sometimes necessary
|
||||||
|
4. **Not using Vite plugin** - PostCSS is valid alternative
|
||||||
|
|
||||||
|
## Review Process
|
||||||
|
|
||||||
|
1. **Check configuration** - Vite/PostCSS setup
|
||||||
|
2. **Review CSS file** - Import syntax, @theme, @utility
|
||||||
|
3. **Scan components** - Utility patterns, container queries
|
||||||
|
4. **Test build** - Verify compilation
|
||||||
|
5. **Visual check** - Confirm styles apply correctly
|
||||||
|
|
||||||
|
## Review Report Template
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## Tailwind v4 Review
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
- [ ] Build tool: [Vite/PostCSS/Other]
|
||||||
|
- [ ] Using correct plugin
|
||||||
|
- [ ] No v3 config file
|
||||||
|
|
||||||
|
### CSS
|
||||||
|
- [ ] Correct import syntax
|
||||||
|
- [ ] Theme variables properly namespaced
|
||||||
|
- [ ] Colors using oklch()
|
||||||
|
- [ ] Animations within @theme
|
||||||
|
|
||||||
|
### Components
|
||||||
|
- [ ] Container queries used correctly
|
||||||
|
- [ ] Semantic naming
|
||||||
|
- [ ] No v3 utility patterns
|
||||||
|
|
||||||
|
### Issues Found
|
||||||
|
1. [Priority] [Description]
|
||||||
|
2. [Priority] [Description]
|
||||||
|
|
||||||
|
### Recommendations
|
||||||
|
- [Specific recommendation]
|
||||||
|
- [Specific recommendation]
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- All other skills in tailwind-4 plugin for detailed patterns
|
||||||
|
- RESEARCH.md for comprehensive v4 documentation
|
||||||
309
skills/using-container-queries/SKILL.md
Normal file
309
skills/using-container-queries/SKILL.md
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
---
|
||||||
|
name: using-container-queries
|
||||||
|
description: Use container queries for component-based responsive design with @container syntax and named containers. Use when building portable, reusable components that adapt to parent size instead of viewport.
|
||||||
|
allowed-tools: Read, Write, Edit, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using Container Queries
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Container queries enable components to respond to their parent container's size instead of the viewport. This creates truly portable, reusable components that work anywhere.
|
||||||
|
|
||||||
|
## Basic Container Queries
|
||||||
|
|
||||||
|
**Step 1: Mark the container**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4 gap-4">
|
||||||
|
<div>Card 1</div>
|
||||||
|
<div>Card 2</div>
|
||||||
|
<div>Card 3</div>
|
||||||
|
<div>Card 4</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
The `@container` class makes an element a container query context.
|
||||||
|
|
||||||
|
**Step 2: Use container breakpoints**
|
||||||
|
|
||||||
|
Container breakpoint utilities use `@` prefix:
|
||||||
|
|
||||||
|
- `@sm:` - Container width ≥ 640px
|
||||||
|
- `@md:` - Container width ≥ 768px
|
||||||
|
- `@lg:` - Container width ≥ 1024px
|
||||||
|
- `@xl:` - Container width ≥ 1280px
|
||||||
|
- `@2xl:` - Container width ≥ 1536px
|
||||||
|
|
||||||
|
## Container vs Viewport Queries
|
||||||
|
|
||||||
|
**Viewport queries (viewport width):**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="grid-cols-1 md:grid-cols-2 lg:grid-cols-3"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Responds to browser window width.
|
||||||
|
|
||||||
|
**Container queries (parent width):**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<div class="grid-cols-1 @md:grid-cols-2 @lg:grid-cols-3"></div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
Responds to parent container width.
|
||||||
|
|
||||||
|
## Named Containers
|
||||||
|
|
||||||
|
Use named containers for nested container queries:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container/main">
|
||||||
|
<div class="@container/sidebar">
|
||||||
|
<div class="flex flex-col @sm/main:flex-row">
|
||||||
|
Main container responsive
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-sm @md/sidebar:text-base">
|
||||||
|
Sidebar container responsive
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Syntax:** `@container/{name}` for the container, `@{breakpoint}/{name}:` for utilities.
|
||||||
|
|
||||||
|
## Portability Patterns
|
||||||
|
|
||||||
|
### Reusable Card Component
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<article class="bg-white rounded-lg shadow-md p-4 @md:p-6">
|
||||||
|
<div class="flex flex-col @md:flex-row @md:gap-6">
|
||||||
|
<img class="w-full @md:w-48 rounded-lg" src="/image.jpg" />
|
||||||
|
|
||||||
|
<div class="flex-1 mt-4 @md:mt-0">
|
||||||
|
<h2 class="text-lg @md:text-xl @lg:text-2xl font-bold">Card Title</h2>
|
||||||
|
|
||||||
|
<p class="mt-2 text-sm @md:text-base text-gray-600">
|
||||||
|
Card description that adapts to container size.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<button class="mt-4 px-3 py-1.5 @md:px-4 @md:py-2 bg-blue-600 text-white rounded-md">
|
||||||
|
Read More
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
This card works in:
|
||||||
|
- Full-width layouts
|
||||||
|
- Sidebar layouts
|
||||||
|
- Grid layouts
|
||||||
|
- Any container size
|
||||||
|
|
||||||
|
### Dashboard Widget
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<div class="bg-white rounded-lg p-4">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<h3 class="text-base @md:text-lg font-semibold">Widget Title</h3>
|
||||||
|
<button class="text-xs @md:text-sm text-blue-600">View All</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4 grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3 gap-3 @md:gap-4">
|
||||||
|
<div class="p-3 bg-gray-50 rounded">Stat 1</div>
|
||||||
|
<div class="p-3 bg-gray-50 rounded">Stat 2</div>
|
||||||
|
<div class="p-3 bg-gray-50 rounded">Stat 3</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Responsive Navigation
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container/nav">
|
||||||
|
<nav class="flex flex-col @md/nav:flex-row @md/nav:items-center gap-2 @md/nav:gap-6">
|
||||||
|
<a href="#" class="text-sm @md/nav:text-base">Home</a>
|
||||||
|
<a href="#" class="text-sm @md/nav:text-base">About</a>
|
||||||
|
<a href="#" class="text-sm @md/nav:text-base">Services</a>
|
||||||
|
<a href="#" class="text-sm @md/nav:text-base">Contact</a>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complex Layout Example
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3 @xl:grid-cols-4 gap-4 @md:gap-6 @lg:gap-8">
|
||||||
|
<div class="@container/card">
|
||||||
|
<article class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||||
|
<div class="relative h-32 @md/card:h-48 bg-gradient-to-br from-blue-500 to-purple-600">
|
||||||
|
<img class="w-full h-full object-cover" src="/image.jpg" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="p-3 @md/card:p-4 @lg/card:p-6">
|
||||||
|
<h3 class="text-base @md/card:text-lg @lg/card:text-xl font-bold">
|
||||||
|
Card Title
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p class="mt-2 text-xs @md/card:text-sm @lg/card:text-base text-gray-600 line-clamp-2 @lg/card:line-clamp-3">
|
||||||
|
Description that adapts based on available space in the card container.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="mt-3 @md/card:mt-4 flex items-center justify-between">
|
||||||
|
<span class="text-xs @md/card:text-sm text-gray-500">2 days ago</span>
|
||||||
|
|
||||||
|
<button class="px-2 py-1 @md/card:px-3 @md/card:py-1.5 text-xs @md/card:text-sm bg-blue-600 text-white rounded">
|
||||||
|
Read
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mixing Container and Viewport Queries
|
||||||
|
|
||||||
|
You can combine both for maximum control:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<div class="
|
||||||
|
grid
|
||||||
|
grid-cols-1
|
||||||
|
md:grid-cols-2
|
||||||
|
lg:grid-cols-3
|
||||||
|
@lg:grid-cols-2
|
||||||
|
@xl:grid-cols-3
|
||||||
|
">
|
||||||
|
Components adapt to both viewport and container
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Order matters:** Viewport queries first, then container queries to override.
|
||||||
|
|
||||||
|
## Container Query Breakpoints
|
||||||
|
|
||||||
|
Default container breakpoints:
|
||||||
|
|
||||||
|
| Breakpoint | Min Width |
|
||||||
|
| ---------- | --------- |
|
||||||
|
| `@xs` | 320px |
|
||||||
|
| `@sm` | 640px |
|
||||||
|
| `@md` | 768px |
|
||||||
|
| `@lg` | 1024px |
|
||||||
|
| `@xl` | 1280px |
|
||||||
|
| `@2xl` | 1536px |
|
||||||
|
|
||||||
|
## Custom Container Breakpoints
|
||||||
|
|
||||||
|
Define custom container breakpoints in theme:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--container-xs: 20rem;
|
||||||
|
--container-sm: 40rem;
|
||||||
|
--container-md: 48rem;
|
||||||
|
--container-lg: 64rem;
|
||||||
|
--container-xl: 80rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
Container queries are highly performant in modern browsers. They:
|
||||||
|
|
||||||
|
- Use native browser APIs
|
||||||
|
- Don't require JavaScript
|
||||||
|
- Trigger efficient reflows
|
||||||
|
- Work with CSS cascade layers
|
||||||
|
|
||||||
|
## Browser Support
|
||||||
|
|
||||||
|
Container queries require:
|
||||||
|
- Safari 16.4+
|
||||||
|
- Chrome 111+
|
||||||
|
- Firefox 128+
|
||||||
|
|
||||||
|
Same as Tailwind v4's minimum browser requirements.
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use for component portability** - Container queries excel at making components work anywhere
|
||||||
|
2. **Name containers when nested** - Use `/name` syntax for clarity
|
||||||
|
3. **Prefer container queries for components** - Use viewport queries for page-level layouts
|
||||||
|
4. **Combine with viewport queries** - Use both for maximum flexibility
|
||||||
|
5. **Test at various sizes** - Verify components work in narrow and wide containers
|
||||||
|
|
||||||
|
## Common Patterns
|
||||||
|
|
||||||
|
### Sidebar Layout
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="flex gap-6">
|
||||||
|
<aside class="w-64 @container/sidebar">
|
||||||
|
<nav class="space-y-2">
|
||||||
|
<a class="block p-2 text-sm @md/sidebar:text-base">Link 1</a>
|
||||||
|
<a class="block p-2 text-sm @md/sidebar:text-base">Link 2</a>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<main class="flex-1 @container/main">
|
||||||
|
<div class="grid grid-cols-1 @lg/main:grid-cols-2 gap-4">
|
||||||
|
<div>Content 1</div>
|
||||||
|
<div>Content 2</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Product Grid
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<div class="grid grid-cols-2 @md:grid-cols-3 @lg:grid-cols-4 @xl:grid-cols-5 gap-4">
|
||||||
|
<div class="@container/product">
|
||||||
|
<div class="bg-white rounded-lg p-3 @md/product:p-4">
|
||||||
|
<img class="w-full aspect-square rounded" src="/product.jpg" />
|
||||||
|
<h3 class="mt-2 text-sm @md/product:text-base font-medium">Product</h3>
|
||||||
|
<p class="mt-1 text-xs @md/product:text-sm text-gray-600">$99</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Form Layout
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="@container">
|
||||||
|
<form class="space-y-4 @md:space-y-6">
|
||||||
|
<div class="grid grid-cols-1 @md:grid-cols-2 gap-4 @md:gap-6">
|
||||||
|
<input class="px-3 py-2 @md:px-4 @md:py-3 border rounded" placeholder="First Name" />
|
||||||
|
<input class="px-3 py-2 @md:px-4 @md:py-3 border rounded" placeholder="Last Name" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="w-full px-4 py-2 @md:px-6 @md:py-3 bg-blue-600 text-white rounded">
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- RESEARCH.md sections: "Container Queries" and "Usage Patterns"
|
||||||
289
skills/using-theme-variables/SKILL.md
Normal file
289
skills/using-theme-variables/SKILL.md
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
---
|
||||||
|
name: using-theme-variables
|
||||||
|
description: Define and use theme variables with @theme directive, oklch() color format, semantic naming, and namespaced utilities. Use when customizing design tokens or creating design systems.
|
||||||
|
allowed-tools: Read, Write, Edit, Grep, Glob
|
||||||
|
---
|
||||||
|
|
||||||
|
# Using Theme Variables
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Define custom design tokens using the `@theme` directive with CSS variables. Tailwind v4 uses modern color formats (oklch) and namespace-based utility generation.
|
||||||
|
|
||||||
|
## Basic Theme Variables
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-display: 'Satoshi', 'sans-serif';
|
||||||
|
--font-body: 'Inter', 'sans-serif';
|
||||||
|
|
||||||
|
--color-brand-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-brand-accent: oklch(0.75 0.22 320);
|
||||||
|
|
||||||
|
--breakpoint-3xl: 120rem;
|
||||||
|
--breakpoint-4xl: 160rem;
|
||||||
|
|
||||||
|
--spacing-18: 4.5rem;
|
||||||
|
--spacing-72: 18rem;
|
||||||
|
|
||||||
|
--radius-4xl: 2rem;
|
||||||
|
|
||||||
|
--shadow-brutal: 8px 8px 0 0 rgb(0 0 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Color Format: oklch()
|
||||||
|
|
||||||
|
Tailwind v4 uses OkLCh color space instead of RGB for wider gamut and more vivid colors on modern displays.
|
||||||
|
|
||||||
|
**oklch() syntax:**
|
||||||
|
|
||||||
|
```
|
||||||
|
oklch(Lightness Chroma Hue)
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Lightness:** 0 (black) to 1 (white)
|
||||||
|
- **Chroma:** 0 (gray) to ~0.4 (vivid)
|
||||||
|
- **Hue:** 0-360 degrees
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-blue: oklch(0.65 0.25 270);
|
||||||
|
--color-green: oklch(0.72 0.15 142);
|
||||||
|
--color-red: oklch(0.65 0.22 25);
|
||||||
|
--color-purple: oklch(0.75 0.22 320);
|
||||||
|
--color-orange: oklch(0.78 0.18 60);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Theme Variable Namespaces
|
||||||
|
|
||||||
|
Tailwind generates utilities based on variable name prefixes:
|
||||||
|
|
||||||
|
| Namespace | Utilities Generated |
|
||||||
|
| ----------------- | ------------------------------------------ |
|
||||||
|
| `--color-*` | bg-, text-, fill-, stroke-, border-, ring- |
|
||||||
|
| `--font-*` | font-family utilities |
|
||||||
|
| `--text-*` | font-size utilities |
|
||||||
|
| `--font-weight-*` | font-weight utilities |
|
||||||
|
| `--tracking-*` | letter-spacing utilities |
|
||||||
|
| `--leading-*` | line-height utilities |
|
||||||
|
| `--breakpoint-*` | responsive breakpoint variants |
|
||||||
|
| `--spacing-*` | padding, margin, sizing utilities |
|
||||||
|
| `--radius-*` | border-radius utilities |
|
||||||
|
| `--shadow-*` | box-shadow utilities |
|
||||||
|
| `--animate-*` | animation utilities |
|
||||||
|
|
||||||
|
**Example usage:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-brand: oklch(0.65 0.25 270);
|
||||||
|
--spacing-18: 4.5rem;
|
||||||
|
--radius-4xl: 2rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Generates utilities:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-brand text-brand border-brand"></div>
|
||||||
|
<div class="p-18 m-18 w-18"></div>
|
||||||
|
<div class="rounded-4xl"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Semantic Naming
|
||||||
|
|
||||||
|
Use meaningful names instead of generic scales:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-secondary: oklch(0.75 0.22 320);
|
||||||
|
--color-success: oklch(0.72 0.15 142);
|
||||||
|
--color-warning: oklch(0.78 0.18 60);
|
||||||
|
--color-error: oklch(0.65 0.22 25);
|
||||||
|
|
||||||
|
--color-text: oklch(0.21 0 0);
|
||||||
|
--color-text-muted: oklch(0.51 0 0);
|
||||||
|
--color-background: oklch(0.99 0 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button class="bg-primary text-white hover:opacity-90">Primary Button</button>
|
||||||
|
<div class="text-error">Error message</div>
|
||||||
|
<p class="text-text-muted">Muted text</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extending Default Theme
|
||||||
|
|
||||||
|
Add new values without removing defaults:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-lagoon: oklch(0.72 0.11 221.19);
|
||||||
|
--color-coral: oklch(0.74 0.17 40.24);
|
||||||
|
--font-script: 'Great Vibes', cursive;
|
||||||
|
--breakpoint-3xl: 120rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
All default Tailwind utilities remain available (blue-500, gray-200, etc.).
|
||||||
|
|
||||||
|
## Replacing Default Theme
|
||||||
|
|
||||||
|
Remove all defaults and define only custom variables:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--*: initial;
|
||||||
|
|
||||||
|
--spacing: 4px;
|
||||||
|
--font-body: 'Inter', sans-serif;
|
||||||
|
--color-lagoon: oklch(0.72 0.11 221.19);
|
||||||
|
--color-coral: oklch(0.74 0.17 40.24);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Only utilities based on custom variables will be generated.
|
||||||
|
|
||||||
|
## Inline Theme Variables
|
||||||
|
|
||||||
|
Reference other variables using the inline option:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme inline {
|
||||||
|
--font-sans: var(--font-inter);
|
||||||
|
--color-primary: var(--color-red-500);
|
||||||
|
--spacing-gutter: var(--spacing-4);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Variables defined in `@theme inline` can reference variables from main `@theme`.
|
||||||
|
|
||||||
|
## Static Theme Variables
|
||||||
|
|
||||||
|
Generate all CSS variables even if unused:
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme static {
|
||||||
|
--color-primary: var(--color-red-500);
|
||||||
|
--color-secondary: var(--color-blue-500);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Useful for runtime JavaScript access:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const styles = getComputedStyle(document.documentElement);
|
||||||
|
const primaryColor = styles.getPropertyValue('--color-primary');
|
||||||
|
```
|
||||||
|
|
||||||
|
## Accessing Variables in JavaScript
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const styles = getComputedStyle(document.documentElement);
|
||||||
|
const shadow = styles.getPropertyValue('--shadow-xl');
|
||||||
|
const color = styles.getPropertyValue('--color-blue-500');
|
||||||
|
```
|
||||||
|
|
||||||
|
**Setting variables dynamically:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
document.documentElement.style.setProperty('--color-primary', 'oklch(0.70 0.20 180)');
|
||||||
|
```
|
||||||
|
|
||||||
|
**In animation libraries:**
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<motion.div animate={{ backgroundColor: 'var(--color-blue-500)' }} />
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sharing Themes Across Projects
|
||||||
|
|
||||||
|
**Create shared theme file:**
|
||||||
|
|
||||||
|
**packages/brand/theme.css:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--*: initial;
|
||||||
|
|
||||||
|
--spacing: 4px;
|
||||||
|
--font-body: 'Inter', sans-serif;
|
||||||
|
--color-lagoon: oklch(0.72 0.11 221.19);
|
||||||
|
--color-coral: oklch(0.74 0.17 40.24);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Import in projects:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
@import '@my-company/brand/theme.css';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complex Theme Example
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
||||||
|
|
||||||
|
--text-xs: 0.75rem;
|
||||||
|
--text-sm: 0.875rem;
|
||||||
|
--text-base: 1rem;
|
||||||
|
--text-lg: 1.125rem;
|
||||||
|
--text-xl: 1.25rem;
|
||||||
|
|
||||||
|
--color-white: #ffffff;
|
||||||
|
--color-black: #000000;
|
||||||
|
|
||||||
|
--color-gray-50: oklch(0.99 0 0);
|
||||||
|
--color-gray-100: oklch(0.97 0 0);
|
||||||
|
--color-gray-900: oklch(0.21 0 0);
|
||||||
|
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-secondary: oklch(0.75 0.22 320);
|
||||||
|
--color-success: oklch(0.72 0.15 142);
|
||||||
|
|
||||||
|
--spacing: 0.25rem;
|
||||||
|
--spacing-px: 1px;
|
||||||
|
--spacing-1: calc(var(--spacing) * 1);
|
||||||
|
--spacing-4: calc(var(--spacing) * 4);
|
||||||
|
|
||||||
|
--radius-md: 0.375rem;
|
||||||
|
--radius-lg: 0.5rem;
|
||||||
|
--radius-full: 9999px;
|
||||||
|
|
||||||
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||||||
|
|
||||||
|
--breakpoint-sm: 40rem;
|
||||||
|
--breakpoint-md: 48rem;
|
||||||
|
--breakpoint-lg: 64rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Use semantic names** instead of scales (primary vs blue-500)
|
||||||
|
2. **Use oklch()** for color definitions
|
||||||
|
3. **Define variables at :root** for performance
|
||||||
|
4. **Group related variables** (colors, spacing, typography)
|
||||||
|
5. **Reference other variables** with inline theme
|
||||||
|
6. **Share themes** across projects using imports
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- references/color-conversion.md - Hex to oklch conversion table
|
||||||
|
- references/namespace-reference.md - Complete namespace documentation
|
||||||
179
skills/using-theme-variables/references/color-conversion.md
Normal file
179
skills/using-theme-variables/references/color-conversion.md
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
# Color Conversion: Hex to oklch()
|
||||||
|
|
||||||
|
## Common Color Conversions
|
||||||
|
|
||||||
|
### Grays
|
||||||
|
|
||||||
|
| Hex | oklch() | Description |
|
||||||
|
| --------- | -------------------- | -------------- |
|
||||||
|
| `#ffffff` | `oklch(1 0 0)` | White |
|
||||||
|
| `#f9fafb` | `oklch(0.99 0 0)` | Gray 50 |
|
||||||
|
| `#f3f4f6` | `oklch(0.97 0 0)` | Gray 100 |
|
||||||
|
| `#e5e7eb` | `oklch(0.93 0 0)` | Gray 200 |
|
||||||
|
| `#d1d5db` | `oklch(0.88 0 0)` | Gray 300 |
|
||||||
|
| `#9ca3af` | `oklch(0.74 0 0)` | Gray 400 |
|
||||||
|
| `#6b7280` | `oklch(0.62 0 0)` | Gray 500 |
|
||||||
|
| `#4b5563` | `oklch(0.51 0 0)` | Gray 600 |
|
||||||
|
| `#374151` | `oklch(0.42 0 0)` | Gray 700 |
|
||||||
|
| `#1f2937` | `oklch(0.31 0 0)` | Gray 800 |
|
||||||
|
| `#111827` | `oklch(0.21 0 0)` | Gray 900 |
|
||||||
|
| `#000000` | `oklch(0 0 0)` | Black |
|
||||||
|
|
||||||
|
### Blues
|
||||||
|
|
||||||
|
| Hex | oklch() | Description |
|
||||||
|
| --------- | -------------------- | -------------- |
|
||||||
|
| `#eff6ff` | `oklch(0.98 0.01 250)` | Blue 50 |
|
||||||
|
| `#dbeafe` | `oklch(0.95 0.03 250)` | Blue 100 |
|
||||||
|
| `#bfdbfe` | `oklch(0.90 0.06 250)` | Blue 200 |
|
||||||
|
| `#93c5fd` | `oklch(0.82 0.10 250)` | Blue 300 |
|
||||||
|
| `#60a5fa` | `oklch(0.73 0.16 250)` | Blue 400 |
|
||||||
|
| `#3b82f6` | `oklch(0.65 0.25 270)` | Blue 500 |
|
||||||
|
| `#2563eb` | `oklch(0.55 0.28 270)` | Blue 600 |
|
||||||
|
| `#1d4ed8` | `oklch(0.47 0.27 270)` | Blue 700 |
|
||||||
|
| `#1e40af` | `oklch(0.40 0.24 270)` | Blue 800 |
|
||||||
|
| `#1e3a8a` | `oklch(0.33 0.20 270)` | Blue 900 |
|
||||||
|
|
||||||
|
### Greens
|
||||||
|
|
||||||
|
| Hex | oklch() | Description |
|
||||||
|
| --------- | -------------------- | -------------- |
|
||||||
|
| `#f0fdf4` | `oklch(0.99 0.01 142)` | Green 50 |
|
||||||
|
| `#dcfce7` | `oklch(0.97 0.03 142)` | Green 100 |
|
||||||
|
| `#bbf7d0` | `oklch(0.93 0.07 142)` | Green 200 |
|
||||||
|
| `#86efac` | `oklch(0.87 0.13 142)` | Green 300 |
|
||||||
|
| `#4ade80` | `oklch(0.79 0.18 142)` | Green 400 |
|
||||||
|
| `#22c55e` | `oklch(0.72 0.15 142)` | Green 500 |
|
||||||
|
| `#16a34a` | `oklch(0.61 0.17 142)` | Green 600 |
|
||||||
|
| `#15803d` | `oklch(0.50 0.15 142)` | Green 700 |
|
||||||
|
| `#166534` | `oklch(0.41 0.13 142)` | Green 800 |
|
||||||
|
| `#14532d` | `oklch(0.33 0.11 142)` | Green 900 |
|
||||||
|
|
||||||
|
### Reds
|
||||||
|
|
||||||
|
| Hex | oklch() | Description |
|
||||||
|
| --------- | -------------------- | -------------- |
|
||||||
|
| `#fef2f2` | `oklch(0.98 0.01 25)` | Red 50 |
|
||||||
|
| `#fee2e2` | `oklch(0.95 0.03 25)` | Red 100 |
|
||||||
|
| `#fecaca` | `oklch(0.90 0.06 25)` | Red 200 |
|
||||||
|
| `#fca5a5` | `oklch(0.82 0.11 25)` | Red 300 |
|
||||||
|
| `#f87171` | `oklch(0.73 0.16 25)` | Red 400 |
|
||||||
|
| `#ef4444` | `oklch(0.65 0.22 25)` | Red 500 |
|
||||||
|
| `#dc2626` | `oklch(0.55 0.24 25)` | Red 600 |
|
||||||
|
| `#b91c1c` | `oklch(0.47 0.22 25)` | Red 700 |
|
||||||
|
| `#991b1b` | `oklch(0.40 0.19 25)` | Red 800 |
|
||||||
|
| `#7f1d1d` | `oklch(0.33 0.16 25)` | Red 900 |
|
||||||
|
|
||||||
|
### Purples
|
||||||
|
|
||||||
|
| Hex | oklch() | Description |
|
||||||
|
| --------- | -------------------- | ---------------- |
|
||||||
|
| `#faf5ff` | `oklch(0.98 0.01 320)` | Purple 50 |
|
||||||
|
| `#f3e8ff` | `oklch(0.95 0.04 320)` | Purple 100 |
|
||||||
|
| `#e9d5ff` | `oklch(0.89 0.08 320)` | Purple 200 |
|
||||||
|
| `#d8b4fe` | `oklch(0.82 0.14 320)` | Purple 300 |
|
||||||
|
| `#c084fc` | `oklch(0.73 0.20 320)` | Purple 400 |
|
||||||
|
| `#a855f7` | `oklch(0.65 0.25 320)` | Purple 500 |
|
||||||
|
| `#9333ea` | `oklch(0.55 0.28 320)` | Purple 600 |
|
||||||
|
| `#7e22ce` | `oklch(0.47 0.27 320)` | Purple 700 |
|
||||||
|
| `#6b21a8` | `oklch(0.40 0.24 320)` | Purple 800 |
|
||||||
|
| `#581c87` | `oklch(0.33 0.20 320)` | Purple 900 |
|
||||||
|
|
||||||
|
### Yellows / Oranges
|
||||||
|
|
||||||
|
| Hex | oklch() | Description |
|
||||||
|
| --------- | -------------------- | ---------------- |
|
||||||
|
| `#fef3c7` | `oklch(0.96 0.05 90)` | Yellow 100 |
|
||||||
|
| `#fde047` | `oklch(0.90 0.15 90)` | Yellow 300 |
|
||||||
|
| `#facc15` | `oklch(0.82 0.18 90)` | Yellow 400 |
|
||||||
|
| `#eab308` | `oklch(0.75 0.20 90)` | Yellow 500 |
|
||||||
|
| `#fed7aa` | `oklch(0.89 0.07 60)` | Orange 200 |
|
||||||
|
| `#fdba74` | `oklch(0.82 0.12 60)` | Orange 300 |
|
||||||
|
| `#fb923c` | `oklch(0.75 0.16 60)` | Orange 400 |
|
||||||
|
| `#f97316` | `oklch(0.68 0.20 60)` | Orange 500 |
|
||||||
|
| `#ea580c` | `oklch(0.60 0.22 60)` | Orange 600 |
|
||||||
|
|
||||||
|
### Teals / Cyans
|
||||||
|
|
||||||
|
| Hex | oklch() | Description |
|
||||||
|
| --------- | ---------------------- | -------------- |
|
||||||
|
| `#ccfbf1` | `oklch(0.95 0.04 180)` | Teal 100 |
|
||||||
|
| `#99f6e4` | `oklch(0.92 0.08 180)` | Teal 200 |
|
||||||
|
| `#5eead4` | `oklch(0.86 0.13 180)` | Teal 300 |
|
||||||
|
| `#2dd4bf` | `oklch(0.79 0.16 180)` | Teal 400 |
|
||||||
|
| `#14b8a6` | `oklch(0.72 0.17 180)` | Teal 500 |
|
||||||
|
| `#cffafe` | `oklch(0.98 0.02 200)` | Cyan 100 |
|
||||||
|
| `#a5f3fc` | `oklch(0.94 0.05 200)` | Cyan 200 |
|
||||||
|
| `#67e8f9` | `oklch(0.88 0.10 200)` | Cyan 300 |
|
||||||
|
| `#22d3ee` | `oklch(0.81 0.15 200)` | Cyan 400 |
|
||||||
|
| `#06b6d4` | `oklch(0.73 0.18 200)` | Cyan 500 |
|
||||||
|
|
||||||
|
## Conversion Tips
|
||||||
|
|
||||||
|
### Understanding oklch() Parameters
|
||||||
|
|
||||||
|
**Lightness (0-1):**
|
||||||
|
- 0.95-1.0: Very light colors (50-100)
|
||||||
|
- 0.80-0.95: Light colors (200-300)
|
||||||
|
- 0.65-0.80: Medium colors (400-500)
|
||||||
|
- 0.45-0.65: Dark colors (600-700)
|
||||||
|
- 0.20-0.45: Very dark colors (800-900)
|
||||||
|
- 0-0.20: Near black
|
||||||
|
|
||||||
|
**Chroma (0-0.4):**
|
||||||
|
- 0: Grayscale
|
||||||
|
- 0.01-0.05: Very muted
|
||||||
|
- 0.05-0.15: Muted
|
||||||
|
- 0.15-0.25: Vibrant
|
||||||
|
- 0.25+: Very vivid
|
||||||
|
|
||||||
|
**Hue (0-360):**
|
||||||
|
- 0-30: Red
|
||||||
|
- 30-60: Orange
|
||||||
|
- 60-90: Yellow
|
||||||
|
- 90-150: Green
|
||||||
|
- 150-210: Cyan/Teal
|
||||||
|
- 210-270: Blue
|
||||||
|
- 270-330: Purple/Violet
|
||||||
|
- 330-360: Magenta/Pink
|
||||||
|
|
||||||
|
## Online Conversion Tools
|
||||||
|
|
||||||
|
1. **OKLCH Color Picker:** https://oklch.com/
|
||||||
|
2. **Evil Martians OKLCH Converter:** https://oklch.evilmartians.io/
|
||||||
|
3. **Colorjs.io:** https://colorjs.io/apps/convert/
|
||||||
|
|
||||||
|
## Manual Conversion Process
|
||||||
|
|
||||||
|
1. Convert hex to RGB
|
||||||
|
2. Use online tool to convert RGB to OkLCh
|
||||||
|
3. Round values to 2 decimal places
|
||||||
|
4. Test in browser to verify appearance
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
```
|
||||||
|
Hex: #3b82f6 (Tailwind Blue 500)
|
||||||
|
RGB: rgb(59, 130, 246)
|
||||||
|
OkLCh: oklch(0.65 0.25 270)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Color Palette Example
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-brand-purple: oklch(0.65 0.25 320);
|
||||||
|
--color-brand-blue: oklch(0.65 0.25 270);
|
||||||
|
--color-brand-teal: oklch(0.72 0.17 180);
|
||||||
|
|
||||||
|
--color-success: oklch(0.72 0.15 142);
|
||||||
|
--color-warning: oklch(0.78 0.18 60);
|
||||||
|
--color-error: oklch(0.65 0.22 25);
|
||||||
|
--color-info: oklch(0.73 0.18 200);
|
||||||
|
|
||||||
|
--color-text: oklch(0.21 0 0);
|
||||||
|
--color-text-muted: oklch(0.51 0 0);
|
||||||
|
--color-background: oklch(0.99 0 0);
|
||||||
|
--color-surface: oklch(1 0 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
450
skills/using-theme-variables/references/namespace-reference.md
Normal file
450
skills/using-theme-variables/references/namespace-reference.md
Normal file
@@ -0,0 +1,450 @@
|
|||||||
|
# Theme Variable Namespace Reference
|
||||||
|
|
||||||
|
## Complete Namespace Documentation
|
||||||
|
|
||||||
|
### Color Namespace: `--color-*`
|
||||||
|
|
||||||
|
**Generates utilities:** bg-, text-, fill-, stroke-, border-, ring-, outline-, decoration-, caret-
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-brand: oklch(0.75 0.22 320);
|
||||||
|
--color-error: oklch(0.65 0.22 25);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-primary text-white border-primary"></div>
|
||||||
|
<svg class="fill-brand stroke-brand"></svg>
|
||||||
|
<input class="ring-error outline-error caret-error" />
|
||||||
|
```
|
||||||
|
|
||||||
|
**With opacity modifiers:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="bg-primary/50 text-brand/75"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Font Family: `--font-*`
|
||||||
|
|
||||||
|
**Generates utilities:** font-{name}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--font-sans: 'Inter', sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
--font-display: 'Satoshi', sans-serif;
|
||||||
|
--font-script: 'Great Vibes', cursive;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<body class="font-sans">
|
||||||
|
<h1 class="font-display">Heading</h1>
|
||||||
|
<code class="font-mono">Code</code>
|
||||||
|
<p class="font-script">Script text</p>
|
||||||
|
</body>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Font Size: `--text-*`
|
||||||
|
|
||||||
|
**Generates utilities:** text-{size}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--text-xs: 0.75rem;
|
||||||
|
--text-sm: 0.875rem;
|
||||||
|
--text-base: 1rem;
|
||||||
|
--text-lg: 1.125rem;
|
||||||
|
--text-xl: 1.25rem;
|
||||||
|
--text-2xl: 1.5rem;
|
||||||
|
--text-3xl: 1.875rem;
|
||||||
|
--text-4xl: 2.25rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="text-sm">Small text</p>
|
||||||
|
<h1 class="text-4xl">Large heading</h1>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Font Weight: `--font-weight-*`
|
||||||
|
|
||||||
|
**Generates utilities:** font-{weight}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--font-weight-thin: 100;
|
||||||
|
--font-weight-light: 300;
|
||||||
|
--font-weight-normal: 400;
|
||||||
|
--font-weight-medium: 500;
|
||||||
|
--font-weight-semibold: 600;
|
||||||
|
--font-weight-bold: 700;
|
||||||
|
--font-weight-black: 900;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="font-light">Light text</p>
|
||||||
|
<strong class="font-bold">Bold text</strong>
|
||||||
|
<h1 class="font-black">Black weight</h1>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Letter Spacing: `--tracking-*`
|
||||||
|
|
||||||
|
**Generates utilities:** tracking-{size}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--tracking-tighter: -0.05em;
|
||||||
|
--tracking-tight: -0.025em;
|
||||||
|
--tracking-normal: 0em;
|
||||||
|
--tracking-wide: 0.025em;
|
||||||
|
--tracking-wider: 0.05em;
|
||||||
|
--tracking-widest: 0.1em;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="tracking-tight">Tight spacing</p>
|
||||||
|
<p class="tracking-wide">Wide spacing</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Line Height: `--leading-*`
|
||||||
|
|
||||||
|
**Generates utilities:** leading-{size}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--leading-none: 1;
|
||||||
|
--leading-tight: 1.25;
|
||||||
|
--leading-snug: 1.375;
|
||||||
|
--leading-normal: 1.5;
|
||||||
|
--leading-relaxed: 1.625;
|
||||||
|
--leading-loose: 2;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<p class="leading-tight">Tight line height</p>
|
||||||
|
<p class="leading-loose">Loose line height</p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Breakpoints: `--breakpoint-*`
|
||||||
|
|
||||||
|
**Generates responsive variants:** {breakpoint}:
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--breakpoint-sm: 40rem;
|
||||||
|
--breakpoint-md: 48rem;
|
||||||
|
--breakpoint-lg: 64rem;
|
||||||
|
--breakpoint-xl: 80rem;
|
||||||
|
--breakpoint-2xl: 96rem;
|
||||||
|
--breakpoint-3xl: 120rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"></div>
|
||||||
|
<p class="text-base lg:text-lg 2xl:text-xl 3xl:text-2xl"></p>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spacing: `--spacing-*`
|
||||||
|
|
||||||
|
**Generates utilities:** p-, m-, w-, h-, gap-, space-, inset-, top-, right-, bottom-, left-
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--spacing: 0.25rem;
|
||||||
|
--spacing-px: 1px;
|
||||||
|
--spacing-0: 0;
|
||||||
|
--spacing-1: calc(var(--spacing) * 1);
|
||||||
|
--spacing-2: calc(var(--spacing) * 2);
|
||||||
|
--spacing-4: calc(var(--spacing) * 4);
|
||||||
|
--spacing-8: calc(var(--spacing) * 8);
|
||||||
|
--spacing-16: calc(var(--spacing) * 16);
|
||||||
|
--spacing-18: 4.5rem;
|
||||||
|
--spacing-72: 18rem;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="p-4 m-2 w-18 h-72"></div>
|
||||||
|
<div class="gap-8 space-x-4"></div>
|
||||||
|
<div class="top-16 left-8"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Border Radius: `--radius-*`
|
||||||
|
|
||||||
|
**Generates utilities:** rounded-{size}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--radius-none: 0;
|
||||||
|
--radius-sm: 0.125rem;
|
||||||
|
--radius-md: 0.375rem;
|
||||||
|
--radius-lg: 0.5rem;
|
||||||
|
--radius-xl: 0.75rem;
|
||||||
|
--radius-2xl: 1rem;
|
||||||
|
--radius-3xl: 1.5rem;
|
||||||
|
--radius-4xl: 2rem;
|
||||||
|
--radius-full: 9999px;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="rounded-md"></div>
|
||||||
|
<button class="rounded-lg"></button>
|
||||||
|
<div class="rounded-4xl"></div>
|
||||||
|
<img class="rounded-full" />
|
||||||
|
```
|
||||||
|
|
||||||
|
### Box Shadow: `--shadow-*`
|
||||||
|
|
||||||
|
**Generates utilities:** shadow-{size}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||||
|
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-2xl: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
||||||
|
--shadow-brutal: 8px 8px 0 0 rgb(0 0 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="shadow-md"></div>
|
||||||
|
<div class="shadow-xl hover:shadow-2xl"></div>
|
||||||
|
<div class="shadow-brutal"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Animations: `--animate-*`
|
||||||
|
|
||||||
|
**Generates utilities:** animate-{name}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--animate-spin: spin 1s linear infinite;
|
||||||
|
--animate-ping: ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
|
||||||
|
--animate-pulse: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
|
--animate-bounce: bounce 1s infinite;
|
||||||
|
--animate-fade-in: fade-in 0.3s ease-out;
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes ping {
|
||||||
|
75%, 100% {
|
||||||
|
transform: scale(2);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% {
|
||||||
|
transform: translateY(-25%);
|
||||||
|
animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: none;
|
||||||
|
animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="animate-spin"></div>
|
||||||
|
<div class="animate-pulse"></div>
|
||||||
|
<div class="animate-fade-in"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Z-Index: `--z-*`
|
||||||
|
|
||||||
|
**Generates utilities:** z-{index}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--z-0: 0;
|
||||||
|
--z-10: 10;
|
||||||
|
--z-20: 20;
|
||||||
|
--z-30: 30;
|
||||||
|
--z-40: 40;
|
||||||
|
--z-50: 50;
|
||||||
|
--z-modal: 100;
|
||||||
|
--z-dropdown: 200;
|
||||||
|
--z-tooltip: 300;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div class="z-10"></div>
|
||||||
|
<div class="z-modal"></div>
|
||||||
|
<div class="z-tooltip"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Aspect Ratio: `--aspect-*`
|
||||||
|
|
||||||
|
**Generates utilities:** aspect-{ratio}
|
||||||
|
|
||||||
|
**Definition:**
|
||||||
|
|
||||||
|
```css
|
||||||
|
@theme {
|
||||||
|
--aspect-auto: auto;
|
||||||
|
--aspect-square: 1 / 1;
|
||||||
|
--aspect-video: 16 / 9;
|
||||||
|
--aspect-portrait: 3 / 4;
|
||||||
|
--aspect-ultrawide: 21 / 9;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
|
||||||
|
```html
|
||||||
|
<img class="aspect-square" />
|
||||||
|
<video class="aspect-video" />
|
||||||
|
<div class="aspect-portrait"></div>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Example
|
||||||
|
|
||||||
|
```css
|
||||||
|
@import 'tailwindcss';
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
--font-sans: 'Inter', -apple-system, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
--font-display: 'Satoshi', sans-serif;
|
||||||
|
|
||||||
|
--text-xs: 0.75rem;
|
||||||
|
--text-sm: 0.875rem;
|
||||||
|
--text-base: 1rem;
|
||||||
|
--text-lg: 1.125rem;
|
||||||
|
--text-xl: 1.25rem;
|
||||||
|
--text-2xl: 1.5rem;
|
||||||
|
|
||||||
|
--font-weight-light: 300;
|
||||||
|
--font-weight-normal: 400;
|
||||||
|
--font-weight-medium: 500;
|
||||||
|
--font-weight-semibold: 600;
|
||||||
|
--font-weight-bold: 700;
|
||||||
|
|
||||||
|
--tracking-tight: -0.025em;
|
||||||
|
--tracking-normal: 0em;
|
||||||
|
--tracking-wide: 0.025em;
|
||||||
|
|
||||||
|
--leading-tight: 1.25;
|
||||||
|
--leading-normal: 1.5;
|
||||||
|
--leading-relaxed: 1.625;
|
||||||
|
|
||||||
|
--color-white: #ffffff;
|
||||||
|
--color-black: #000000;
|
||||||
|
--color-gray-50: oklch(0.99 0 0);
|
||||||
|
--color-gray-900: oklch(0.21 0 0);
|
||||||
|
|
||||||
|
--color-primary: oklch(0.65 0.25 270);
|
||||||
|
--color-secondary: oklch(0.75 0.22 320);
|
||||||
|
--color-success: oklch(0.72 0.15 142);
|
||||||
|
--color-error: oklch(0.65 0.22 25);
|
||||||
|
|
||||||
|
--spacing: 0.25rem;
|
||||||
|
--spacing-1: calc(var(--spacing) * 1);
|
||||||
|
--spacing-2: calc(var(--spacing) * 2);
|
||||||
|
--spacing-4: calc(var(--spacing) * 4);
|
||||||
|
--spacing-8: calc(var(--spacing) * 8);
|
||||||
|
|
||||||
|
--radius-sm: 0.125rem;
|
||||||
|
--radius-md: 0.375rem;
|
||||||
|
--radius-lg: 0.5rem;
|
||||||
|
--radius-full: 9999px;
|
||||||
|
|
||||||
|
--shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
|
||||||
|
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
|
||||||
|
|
||||||
|
--breakpoint-sm: 40rem;
|
||||||
|
--breakpoint-md: 48rem;
|
||||||
|
--breakpoint-lg: 64rem;
|
||||||
|
--breakpoint-xl: 80rem;
|
||||||
|
|
||||||
|
--animate-spin: spin 1s linear infinite;
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user