Initial commit
This commit is contained in:
483
skills/ui-styling/references/tailwind-customization.md
Normal file
483
skills/ui-styling/references/tailwind-customization.md
Normal file
@@ -0,0 +1,483 @@
|
||||
# Tailwind CSS Customization
|
||||
|
||||
Config file structure, custom utilities, plugins, and theme extensions.
|
||||
|
||||
## @theme Directive
|
||||
|
||||
Modern approach to customize Tailwind using CSS:
|
||||
|
||||
```css
|
||||
@import "tailwindcss";
|
||||
|
||||
@theme {
|
||||
/* Custom colors */
|
||||
--color-brand-50: oklch(0.97 0.02 264);
|
||||
--color-brand-500: oklch(0.55 0.22 264);
|
||||
--color-brand-900: oklch(0.25 0.15 264);
|
||||
|
||||
/* Custom fonts */
|
||||
--font-display: "Satoshi", "Inter", sans-serif;
|
||||
--font-body: "Inter", system-ui, sans-serif;
|
||||
|
||||
/* Custom spacing */
|
||||
--spacing-18: calc(var(--spacing) * 18);
|
||||
--spacing-navbar: 4.5rem;
|
||||
|
||||
/* Custom breakpoints */
|
||||
--breakpoint-3xl: 120rem;
|
||||
--breakpoint-tablet: 48rem;
|
||||
|
||||
/* Custom shadows */
|
||||
--shadow-glow: 0 0 20px rgba(139, 92, 246, 0.3);
|
||||
|
||||
/* Custom radius */
|
||||
--radius-large: 1.5rem;
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```html
|
||||
<div class="bg-brand-500 font-display shadow-glow rounded-large">
|
||||
Custom themed element
|
||||
</div>
|
||||
|
||||
<div class="tablet:grid-cols-2 3xl:grid-cols-6">
|
||||
Custom breakpoints
|
||||
</div>
|
||||
```
|
||||
|
||||
## Color Customization
|
||||
|
||||
### Custom Color Palette
|
||||
|
||||
```css
|
||||
@theme {
|
||||
/* Full color scale */
|
||||
--color-primary-50: oklch(0.98 0.02 250);
|
||||
--color-primary-100: oklch(0.95 0.05 250);
|
||||
--color-primary-200: oklch(0.90 0.10 250);
|
||||
--color-primary-300: oklch(0.85 0.15 250);
|
||||
--color-primary-400: oklch(0.75 0.18 250);
|
||||
--color-primary-500: oklch(0.65 0.22 250);
|
||||
--color-primary-600: oklch(0.55 0.22 250);
|
||||
--color-primary-700: oklch(0.45 0.20 250);
|
||||
--color-primary-800: oklch(0.35 0.18 250);
|
||||
--color-primary-900: oklch(0.25 0.15 250);
|
||||
--color-primary-950: oklch(0.15 0.10 250);
|
||||
}
|
||||
```
|
||||
|
||||
### Semantic Colors
|
||||
|
||||
```css
|
||||
@theme {
|
||||
--color-success: oklch(0.65 0.18 145);
|
||||
--color-warning: oklch(0.75 0.15 85);
|
||||
--color-error: oklch(0.60 0.22 25);
|
||||
--color-info: oklch(0.65 0.18 240);
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div class="bg-success text-white">Success message</div>
|
||||
<div class="border-error">Error state</div>
|
||||
```
|
||||
|
||||
## Typography Customization
|
||||
|
||||
### Custom Fonts
|
||||
|
||||
```css
|
||||
@theme {
|
||||
--font-sans: "Inter", system-ui, sans-serif;
|
||||
--font-serif: "Merriweather", Georgia, serif;
|
||||
--font-mono: "JetBrains Mono", Consolas, monospace;
|
||||
--font-display: "Playfair Display", serif;
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<h1 class="font-display">Display heading</h1>
|
||||
<p class="font-sans">Body text</p>
|
||||
<code class="font-mono">Code block</code>
|
||||
```
|
||||
|
||||
### Custom Font Sizes
|
||||
|
||||
```css
|
||||
@theme {
|
||||
--font-size-xs: 0.75rem;
|
||||
--font-size-sm: 0.875rem;
|
||||
--font-size-base: 1rem;
|
||||
--font-size-lg: 1.125rem;
|
||||
--font-size-xl: 1.25rem;
|
||||
--font-size-2xl: 1.5rem;
|
||||
--font-size-3xl: 1.875rem;
|
||||
--font-size-4xl: 2.25rem;
|
||||
--font-size-5xl: 3rem;
|
||||
--font-size-jumbo: 4rem;
|
||||
}
|
||||
```
|
||||
|
||||
## Spacing Customization
|
||||
|
||||
```css
|
||||
@theme {
|
||||
/* Add custom spacing values */
|
||||
--spacing-13: calc(var(--spacing) * 13);
|
||||
--spacing-15: calc(var(--spacing) * 15);
|
||||
--spacing-18: calc(var(--spacing) * 18);
|
||||
|
||||
/* Named spacing */
|
||||
--spacing-header: 4rem;
|
||||
--spacing-footer: 3rem;
|
||||
--spacing-section: 6rem;
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div class="p-18">Custom padding</div>
|
||||
<section class="py-section">Section spacing</section>
|
||||
```
|
||||
|
||||
## Custom Utilities
|
||||
|
||||
Create reusable utility classes:
|
||||
|
||||
```css
|
||||
@utility content-auto {
|
||||
content-visibility: auto;
|
||||
}
|
||||
|
||||
@utility tab-* {
|
||||
tab-size: var(--tab-size-*);
|
||||
}
|
||||
|
||||
@utility 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">Optimized rendering</div>
|
||||
<pre class="tab-4">Code with 4-space tabs</pre>
|
||||
<div class="glass">Glassmorphism effect</div>
|
||||
```
|
||||
|
||||
## Custom Variants
|
||||
|
||||
Create custom state variants:
|
||||
|
||||
```css
|
||||
@custom-variant theme-midnight (&:where([data-theme="midnight"] *));
|
||||
@custom-variant aria-checked (&[aria-checked="true"]);
|
||||
@custom-variant required (&:required);
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```html
|
||||
<div data-theme="midnight">
|
||||
<div class="theme-midnight:bg-navy-900">
|
||||
Applies in midnight theme
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input class="required:border-red-500" required />
|
||||
```
|
||||
|
||||
## Layer Organization
|
||||
|
||||
Organize CSS into layers:
|
||||
|
||||
```css
|
||||
@layer base {
|
||||
h1 {
|
||||
@apply text-4xl font-bold tracking-tight;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-3xl font-semibold;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-blue-600 hover:text-blue-700 underline-offset-4 hover:underline;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-background text-foreground antialiased;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
.btn {
|
||||
@apply px-4 py-2 rounded-lg font-medium transition-colors;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
@apply bg-blue-600 text-white hover:bg-blue-700;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
@apply bg-gray-200 text-gray-900 hover:bg-gray-300;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white rounded-xl shadow-md p-6 hover:shadow-lg transition-shadow;
|
||||
}
|
||||
|
||||
.input {
|
||||
@apply w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent;
|
||||
}
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.text-balance {
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.scrollbar-hide {
|
||||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
}
|
||||
.scrollbar-hide::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## @apply Directive
|
||||
|
||||
Extract repeated utility patterns:
|
||||
|
||||
```css
|
||||
.btn-primary {
|
||||
@apply bg-blue-600 hover:bg-blue-700 active:bg-blue-800 text-white font-semibold px-6 py-3 rounded-lg shadow-md hover:shadow-lg transition-all duration-200 focus:outline-none focus:ring-4 focus:ring-blue-300;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
@apply w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed;
|
||||
}
|
||||
|
||||
.section-container {
|
||||
@apply container mx-auto px-4 sm:px-6 lg:px-8 max-w-7xl;
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```html
|
||||
<button class="btn-primary">Click me</button>
|
||||
<input class="input-field" />
|
||||
<div class="section-container">Content</div>
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
### Official Plugins
|
||||
|
||||
```bash
|
||||
npm install -D @tailwindcss/typography @tailwindcss/forms @tailwindcss/container-queries
|
||||
```
|
||||
|
||||
```javascript
|
||||
// tailwind.config.js
|
||||
export default {
|
||||
plugins: [
|
||||
require('@tailwindcss/typography'),
|
||||
require('@tailwindcss/forms'),
|
||||
require('@tailwindcss/container-queries'),
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
**Typography plugin:**
|
||||
```html
|
||||
<article class="prose lg:prose-xl">
|
||||
<h1>Styled article</h1>
|
||||
<p>Automatically styled prose content</p>
|
||||
</article>
|
||||
```
|
||||
|
||||
**Forms plugin:**
|
||||
```html
|
||||
<!-- Automatically styled form elements -->
|
||||
<input type="text" />
|
||||
<select></select>
|
||||
<textarea></textarea>
|
||||
```
|
||||
|
||||
### Custom Plugin
|
||||
|
||||
```javascript
|
||||
// tailwind.config.js
|
||||
const plugin = require('tailwindcss/plugin')
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
plugin(function({ addUtilities, addComponents, theme }) {
|
||||
// Add utilities
|
||||
addUtilities({
|
||||
'.text-shadow': {
|
||||
textShadow: '2px 2px 4px rgba(0, 0, 0, 0.1)',
|
||||
},
|
||||
'.text-shadow-lg': {
|
||||
textShadow: '4px 4px 8px rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
})
|
||||
|
||||
// Add components
|
||||
addComponents({
|
||||
'.card-custom': {
|
||||
backgroundColor: theme('colors.white'),
|
||||
borderRadius: theme('borderRadius.lg'),
|
||||
padding: theme('spacing.6'),
|
||||
boxShadow: theme('boxShadow.md'),
|
||||
},
|
||||
})
|
||||
}),
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Complete Tailwind Config
|
||||
|
||||
```javascript
|
||||
// tailwind.config.ts
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
const config: Config = {
|
||||
darkMode: ["class"],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
brand: {
|
||||
50: '#f0f9ff',
|
||||
500: '#3b82f6',
|
||||
900: '#1e3a8a',
|
||||
},
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', 'system-ui', 'sans-serif'],
|
||||
display: ['Playfair Display', 'serif'],
|
||||
},
|
||||
spacing: {
|
||||
'18': '4.5rem',
|
||||
'88': '22rem',
|
||||
'128': '32rem',
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
keyframes: {
|
||||
"slide-in": {
|
||||
"0%": { transform: "translateX(-100%)" },
|
||||
"100%": { transform: "translateX(0)" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"slide-in": "slide-in 0.5s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require("tailwindcss-animate")],
|
||||
}
|
||||
|
||||
export default config
|
||||
```
|
||||
|
||||
## Dark Mode Configuration
|
||||
|
||||
```javascript
|
||||
// tailwind.config.js
|
||||
export default {
|
||||
darkMode: ["class"], // or "media" for automatic
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Usage:**
|
||||
```html
|
||||
<!-- Class-based -->
|
||||
<html class="dark">
|
||||
<div class="bg-white dark:bg-gray-900">
|
||||
Responds to .dark class
|
||||
</div>
|
||||
</html>
|
||||
|
||||
<!-- Media query-based -->
|
||||
<div class="bg-white dark:bg-gray-900">
|
||||
Responds to system preference automatically
|
||||
</div>
|
||||
```
|
||||
|
||||
## Content Configuration
|
||||
|
||||
Specify files to scan for classes:
|
||||
|
||||
```javascript
|
||||
// tailwind.config.js
|
||||
export default {
|
||||
content: [
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
"./app/**/*.{js,jsx,ts,tsx}",
|
||||
"./components/**/*.{js,jsx,ts,tsx}",
|
||||
"./pages/**/*.{js,jsx,ts,tsx}",
|
||||
],
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Safelist
|
||||
|
||||
Preserve dynamic classes:
|
||||
|
||||
```javascript
|
||||
export default {
|
||||
safelist: [
|
||||
'bg-red-500',
|
||||
'bg-green-500',
|
||||
'bg-blue-500',
|
||||
{
|
||||
pattern: /bg-(red|green|blue)-(100|500|900)/,
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use @theme for simple customizations**: Prefer CSS-based customization
|
||||
2. **Extract components sparingly**: Use @apply only for truly repeated patterns
|
||||
3. **Leverage design tokens**: Define custom tokens in @theme
|
||||
4. **Layer organization**: Keep base, components, and utilities separate
|
||||
5. **Plugin for complex logic**: Use plugins for advanced customizations
|
||||
6. **Test dark mode**: Ensure custom colors work in both themes
|
||||
7. **Document custom utilities**: Add comments explaining custom classes
|
||||
8. **Semantic naming**: Use descriptive names (primary not blue)
|
||||
Reference in New Issue
Block a user