Initial commit
This commit is contained in:
320
skills/ui-styling/references/canvas-design-system.md
Normal file
320
skills/ui-styling/references/canvas-design-system.md
Normal file
@@ -0,0 +1,320 @@
|
||||
# Canvas Design System
|
||||
|
||||
Visual design philosophy, systematic composition, and sophisticated visual communication.
|
||||
|
||||
## Design Philosophy Approach
|
||||
|
||||
Canvas design operates through two-phase process:
|
||||
|
||||
### Phase 1: Design Philosophy Creation
|
||||
|
||||
Create visual philosophy - aesthetic movement expressed through form, space, color, composition. Not layouts or templates, but pure visual philosophy.
|
||||
|
||||
**What is created:** Design manifesto emphasizing:
|
||||
- Visual expression over text
|
||||
- Spatial communication
|
||||
- Artistic interpretation
|
||||
- Minimal words as visual accent
|
||||
|
||||
**Philosophy structure (4-6 paragraphs):**
|
||||
- Space and form principles
|
||||
- Color and material approach
|
||||
- Scale and rhythm guidance
|
||||
- Composition and balance rules
|
||||
- Visual hierarchy system
|
||||
|
||||
### Phase 2: Visual Expression
|
||||
|
||||
Express philosophy through canvas artifacts:
|
||||
- 90% visual design
|
||||
- 10% essential text
|
||||
- Museum-quality execution
|
||||
- Systematic patterns
|
||||
- Sophisticated composition
|
||||
|
||||
## Core Principles
|
||||
|
||||
### 1. Visual Communication First
|
||||
|
||||
Information lives in design, not paragraphs. Express ideas through:
|
||||
- Color zones and fields
|
||||
- Geometric precision
|
||||
- Spatial relationships
|
||||
- Visual weight and tension
|
||||
- Form and structure
|
||||
|
||||
### 2. Minimal Text Integration
|
||||
|
||||
Text as rare, powerful gesture:
|
||||
- Never paragraphs
|
||||
- Only essential words
|
||||
- Integrated into visual architecture
|
||||
- Small labels, huge impact
|
||||
- Typography as visual element
|
||||
|
||||
### 3. Expert Craftsmanship
|
||||
|
||||
Work must appear:
|
||||
- Meticulously crafted
|
||||
- Labored over with care
|
||||
- Product of countless hours
|
||||
- From absolute top of field
|
||||
- Master-level execution
|
||||
|
||||
### 4. Systematic Patterns
|
||||
|
||||
Use scientific visual language:
|
||||
- Repeating patterns
|
||||
- Perfect shapes
|
||||
- Dense accumulation of marks
|
||||
- Layered elements
|
||||
- Patient repetition rewards sustained viewing
|
||||
|
||||
## Design Movement Examples
|
||||
|
||||
### Concrete Poetry
|
||||
**Philosophy:** Communication through monumental form and bold geometry.
|
||||
|
||||
**Expression:**
|
||||
- Massive color blocks
|
||||
- Sculptural typography (huge words, tiny labels)
|
||||
- Brutalist spatial divisions
|
||||
- Polish poster energy meets Le Corbusier
|
||||
- Ideas through visual weight and spatial tension
|
||||
- Text as rare, powerful gesture
|
||||
|
||||
### Chromatic Language
|
||||
**Philosophy:** Color as primary information system.
|
||||
|
||||
**Expression:**
|
||||
- Geometric precision
|
||||
- Color zones create meaning
|
||||
- Typography minimal - small sans-serif labels
|
||||
- Josef Albers' interaction meets data visualization
|
||||
- Information encoded spatially and chromatically
|
||||
- Words only anchor what color shows
|
||||
|
||||
### Analog Meditation
|
||||
**Philosophy:** Quiet visual contemplation through texture and breathing room.
|
||||
|
||||
**Expression:**
|
||||
- Paper grain, ink bleeds
|
||||
- Vast negative space
|
||||
- Photography and illustration dominate
|
||||
- Typography whispered (small, restrained)
|
||||
- Japanese photobook aesthetic
|
||||
- Images breathe across pages
|
||||
- Text appears sparingly - short phrases only
|
||||
|
||||
### Organic Systems
|
||||
**Philosophy:** Natural clustering and modular growth patterns.
|
||||
|
||||
**Expression:**
|
||||
- Rounded forms
|
||||
- Organic arrangements
|
||||
- Color from nature through architecture
|
||||
- Information through visual diagrams
|
||||
- Spatial relationships and iconography
|
||||
- Text only for key labels floating in space
|
||||
- Composition tells story through spatial orchestration
|
||||
|
||||
### Geometric Silence
|
||||
**Philosophy:** Pure order and restraint.
|
||||
|
||||
**Expression:**
|
||||
- Grid-based precision
|
||||
- Bold photography or stark graphics
|
||||
- Dramatic negative space
|
||||
- Typography precise but minimal
|
||||
- Small essential text, large quiet zones
|
||||
- Swiss formalism meets Brutalist material honesty
|
||||
- Structure communicates, not words
|
||||
- Every alignment from countless refinements
|
||||
|
||||
## Implementation Guidelines
|
||||
|
||||
### Subtle Reference Integration
|
||||
|
||||
Embed conceptual DNA without announcing:
|
||||
- Niche reference woven invisibly
|
||||
- Those who know feel it intuitively
|
||||
- Others experience masterful abstract composition
|
||||
- Like jazz musician quoting another song
|
||||
- Sophisticated, never literal
|
||||
- Reference enhances depth quietly
|
||||
|
||||
### Color Approach
|
||||
|
||||
**Intentional palette:**
|
||||
- Limited colors (2-5)
|
||||
- Cohesive system
|
||||
- Purposeful relationships
|
||||
- oklch color space for precision
|
||||
- Each shade carries meaning
|
||||
|
||||
**Example palette:**
|
||||
```
|
||||
--color-primary: oklch(0.55 0.22 264)
|
||||
--color-accent: oklch(0.75 0.18 45)
|
||||
--color-neutral: oklch(0.90 0.02 264)
|
||||
--color-dark: oklch(0.25 0.15 264)
|
||||
```
|
||||
|
||||
### Typography System
|
||||
|
||||
**Thin fonts preferred:**
|
||||
- Light weights (200-300)
|
||||
- Clean sans-serifs
|
||||
- Geometric precision
|
||||
- Small sizes for labels
|
||||
- Large sizes for impact moments
|
||||
|
||||
**Font integration:**
|
||||
- Search `./canvas-fonts` directory
|
||||
- Download needed fonts
|
||||
- Bring typography onto canvas
|
||||
- Part of art, not typeset digitally
|
||||
|
||||
### Composition Rules
|
||||
|
||||
**Systematic approach:**
|
||||
- Repeating patterns establish rhythm
|
||||
- Perfect geometric shapes
|
||||
- Clinical typography
|
||||
- Reference markers suggest imaginary discipline
|
||||
- Dense accumulation builds meaning
|
||||
- Layered patterns reward attention
|
||||
|
||||
**Spacing discipline:**
|
||||
- Nothing falls off page
|
||||
- Nothing overlaps
|
||||
- Every element within canvas boundaries
|
||||
- Proper margins non-negotiable
|
||||
- Breathing room and clear separation
|
||||
- Professional execution mandatory
|
||||
|
||||
### Canvas Boundaries
|
||||
|
||||
**Technical specs:**
|
||||
- Single page default (multi-page when requested)
|
||||
- PDF or PNG output
|
||||
- High resolution
|
||||
- Clean margins
|
||||
- Contained composition
|
||||
- Flawless formatting
|
||||
|
||||
## Multi-Page Design Systems
|
||||
|
||||
When creating multiple pages:
|
||||
|
||||
### Approach
|
||||
- Treat first page as single page in coffee table book
|
||||
- Create more pages along same philosophy
|
||||
- Distinctly different but cohesive
|
||||
- Pages tell story tastefully
|
||||
- Full creative freedom
|
||||
|
||||
### Consistency Elements
|
||||
- Shared color palette
|
||||
- Consistent typography system
|
||||
- Related compositional approach
|
||||
- Visual language continuity
|
||||
- Philosophical thread throughout
|
||||
|
||||
### Variation Strategy
|
||||
- Unique twist per page
|
||||
- Different focal points
|
||||
- Varied spatial arrangements
|
||||
- Complementary patterns
|
||||
- Progressive visual narrative
|
||||
|
||||
## Execution Checklist
|
||||
|
||||
Before finalizing:
|
||||
|
||||
- [ ] Philosophy guides every decision
|
||||
- [ ] 90% visual, 10% text maximum
|
||||
- [ ] Text minimal and integrated
|
||||
- [ ] Nothing overlaps or falls off page
|
||||
- [ ] Margins and spacing pristine
|
||||
- [ ] Composition cohesive with art
|
||||
- [ ] Appears meticulously crafted
|
||||
- [ ] Master-level execution evident
|
||||
- [ ] Sophisticated, never amateur
|
||||
- [ ] Could be displayed in museum
|
||||
- [ ] Proves undeniable expertise
|
||||
- [ ] Formatting flawless
|
||||
- [ ] Every detail perfect
|
||||
|
||||
## Quality Standards
|
||||
|
||||
### What to Avoid
|
||||
- Cartoony aesthetics
|
||||
- Amateur execution
|
||||
- Text-heavy composition
|
||||
- Random placement
|
||||
- Overlapping elements
|
||||
- Inconsistent spacing
|
||||
- Obvious AI generation
|
||||
- Lack of refinement
|
||||
|
||||
### What to Achieve
|
||||
- Museum quality
|
||||
- Magazine worthy
|
||||
- Art object status
|
||||
- Countless hours appearance
|
||||
- Top-of-field craftsmanship
|
||||
- Philosophical coherence
|
||||
- Visual sophistication
|
||||
- Systematic precision
|
||||
|
||||
## Refinement Process
|
||||
|
||||
### Initial Pass
|
||||
Create based on philosophy and principles.
|
||||
|
||||
### Second Pass (Critical)
|
||||
- Don't add more graphics
|
||||
- Refine what exists
|
||||
- Make extremely crisp
|
||||
- Respect minimalism philosophy
|
||||
- Increase cohesion with art
|
||||
- Make existing elements more artistic
|
||||
- Polish rather than expand
|
||||
|
||||
### Final Verification
|
||||
User already said: "It isn't perfect enough. Must be pristine, masterpiece of craftsmanship, as if about to be displayed in museum."
|
||||
|
||||
Apply this standard before delivery.
|
||||
|
||||
## Output Format
|
||||
|
||||
**Required files:**
|
||||
1. Design philosophy (.md file)
|
||||
2. Visual expression (.pdf or .png)
|
||||
|
||||
**Philosophy file contains:**
|
||||
- Movement name
|
||||
- 4-6 paragraph philosophy
|
||||
- Visual principles
|
||||
- Execution guidance
|
||||
|
||||
**Canvas file contains:**
|
||||
- Visual interpretation
|
||||
- Minimal text
|
||||
- Systematic composition
|
||||
- Expert-level execution
|
||||
|
||||
## Use Cases
|
||||
|
||||
Apply canvas design for:
|
||||
- Brand identity systems
|
||||
- Poster designs
|
||||
- Visual manifestos
|
||||
- Design system documentation
|
||||
- Art pieces and compositions
|
||||
- Conceptual visual frameworks
|
||||
- Editorial design
|
||||
- Exhibition materials
|
||||
- Coffee table books
|
||||
- Design philosophy demonstrations
|
||||
471
skills/ui-styling/references/shadcn-accessibility.md
Normal file
471
skills/ui-styling/references/shadcn-accessibility.md
Normal file
@@ -0,0 +1,471 @@
|
||||
# shadcn/ui Accessibility Patterns
|
||||
|
||||
ARIA patterns, keyboard navigation, screen reader support, and accessible component usage.
|
||||
|
||||
## Foundation: Radix UI Primitives
|
||||
|
||||
shadcn/ui built on Radix UI primitives - unstyled, accessible components following WAI-ARIA design patterns.
|
||||
|
||||
Benefits:
|
||||
- Keyboard navigation built-in
|
||||
- Screen reader announcements
|
||||
- Focus management
|
||||
- ARIA attributes automatically applied
|
||||
- Tested against accessibility standards
|
||||
|
||||
## Keyboard Navigation
|
||||
|
||||
### Focus Management
|
||||
|
||||
**Focus visible states:**
|
||||
```tsx
|
||||
<Button className="focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
|
||||
Accessible Button
|
||||
</Button>
|
||||
```
|
||||
|
||||
**Skip to content:**
|
||||
```tsx
|
||||
<a href="#main-content" className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2">
|
||||
Skip to content
|
||||
</a>
|
||||
|
||||
<main id="main-content">
|
||||
{/* Content */}
|
||||
</main>
|
||||
```
|
||||
|
||||
### Dialog/Modal Navigation
|
||||
|
||||
Dialogs trap focus automatically via Radix Dialog primitive:
|
||||
|
||||
```tsx
|
||||
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"
|
||||
|
||||
<Dialog>
|
||||
<DialogTrigger>Open</DialogTrigger>
|
||||
<DialogContent>
|
||||
{/* Focus trapped here */}
|
||||
<input /> {/* Auto-focused */}
|
||||
<Button>Action</Button>
|
||||
{/* Esc to close, Tab to navigate */}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
```
|
||||
|
||||
Features:
|
||||
- Focus trapped within dialog
|
||||
- Esc key closes
|
||||
- Tab cycles through focusable elements
|
||||
- Focus returns to trigger on close
|
||||
|
||||
### Dropdown/Menu Navigation
|
||||
|
||||
```tsx
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>Open</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Settings</DropdownMenuItem>
|
||||
<DropdownMenuItem>Logout</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
```
|
||||
|
||||
Keyboard shortcuts:
|
||||
- `Space/Enter`: Open menu
|
||||
- `Arrow Up/Down`: Navigate items
|
||||
- `Esc`: Close menu
|
||||
- `Tab`: Close and move focus
|
||||
|
||||
### Command Palette Navigation
|
||||
|
||||
```tsx
|
||||
import { Command } from "@/components/ui/command"
|
||||
|
||||
<Command>
|
||||
<CommandInput placeholder="Search..." />
|
||||
<CommandList>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>Calendar</CommandItem>
|
||||
<CommandItem>Search</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
```
|
||||
|
||||
Features:
|
||||
- Type to filter
|
||||
- Arrow keys to navigate
|
||||
- Enter to select
|
||||
- Esc to close
|
||||
|
||||
## Screen Reader Support
|
||||
|
||||
### Semantic HTML
|
||||
|
||||
Use proper HTML elements:
|
||||
|
||||
```tsx
|
||||
// Good: Semantic HTML
|
||||
<button>Click me</button>
|
||||
<nav><a href="/">Home</a></nav>
|
||||
|
||||
// Avoid: Div soup
|
||||
<div onClick={handler}>Click me</div>
|
||||
```
|
||||
|
||||
### ARIA Labels
|
||||
|
||||
**Label interactive elements:**
|
||||
```tsx
|
||||
<Button aria-label="Close dialog">
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<Input aria-label="Email address" type="email" />
|
||||
```
|
||||
|
||||
**Describe elements:**
|
||||
```tsx
|
||||
<Button aria-describedby="delete-description">
|
||||
Delete Account
|
||||
</Button>
|
||||
<p id="delete-description" className="sr-only">
|
||||
This action permanently deletes your account and cannot be undone
|
||||
</p>
|
||||
```
|
||||
|
||||
### Screen Reader Only Text
|
||||
|
||||
Use `sr-only` class for screen reader only content:
|
||||
|
||||
```tsx
|
||||
<Button>
|
||||
<Trash className="h-4 w-4" />
|
||||
<span className="sr-only">Delete item</span>
|
||||
</Button>
|
||||
|
||||
// CSS for sr-only
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Live Regions
|
||||
|
||||
Announce dynamic content:
|
||||
|
||||
```tsx
|
||||
<div aria-live="polite" aria-atomic="true">
|
||||
{message}
|
||||
</div>
|
||||
|
||||
// For urgent updates
|
||||
<div aria-live="assertive">
|
||||
{error}
|
||||
</div>
|
||||
```
|
||||
|
||||
Toast component includes live region:
|
||||
```tsx
|
||||
const { toast } = useToast()
|
||||
|
||||
toast({
|
||||
title: "Success",
|
||||
description: "Profile updated"
|
||||
})
|
||||
// Announced to screen readers automatically
|
||||
```
|
||||
|
||||
## Form Accessibility
|
||||
|
||||
### Labels and Descriptions
|
||||
|
||||
**Always label inputs:**
|
||||
```tsx
|
||||
import { Label } from "@/components/ui/label"
|
||||
import { Input } from "@/components/ui/input"
|
||||
|
||||
<div>
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input id="email" type="email" />
|
||||
</div>
|
||||
```
|
||||
|
||||
**Add descriptions:**
|
||||
```tsx
|
||||
import { FormDescription, FormMessage } from "@/components/ui/form"
|
||||
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
Your public display name
|
||||
</FormDescription>
|
||||
<FormMessage /> {/* Error messages */}
|
||||
</FormItem>
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
Announce errors to screen readers:
|
||||
|
||||
```tsx
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="email"
|
||||
render={({ field, fieldState }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
aria-invalid={!!fieldState.error}
|
||||
aria-describedby={fieldState.error ? "email-error" : undefined}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage id="email-error" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
```
|
||||
|
||||
### Required Fields
|
||||
|
||||
Indicate required fields:
|
||||
|
||||
```tsx
|
||||
<Label htmlFor="name">
|
||||
Name <span className="text-destructive">*</span>
|
||||
<span className="sr-only">(required)</span>
|
||||
</Label>
|
||||
<Input id="name" required />
|
||||
```
|
||||
|
||||
### Fieldset and Legend
|
||||
|
||||
Group related fields:
|
||||
|
||||
```tsx
|
||||
<fieldset>
|
||||
<legend className="text-lg font-semibold mb-4">
|
||||
Contact Information
|
||||
</legend>
|
||||
<div className="space-y-4">
|
||||
<FormField name="email" />
|
||||
<FormField name="phone" />
|
||||
</div>
|
||||
</fieldset>
|
||||
```
|
||||
|
||||
## Component-Specific Patterns
|
||||
|
||||
### Accordion
|
||||
|
||||
```tsx
|
||||
import { Accordion } from "@/components/ui/accordion"
|
||||
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>
|
||||
{/* Includes aria-expanded, aria-controls automatically */}
|
||||
Is it accessible?
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
{/* Hidden when collapsed, announced when expanded */}
|
||||
Yes. Follows WAI-ARIA design pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
### Tabs
|
||||
|
||||
```tsx
|
||||
import { Tabs } from "@/components/ui/tabs"
|
||||
|
||||
<Tabs defaultValue="account">
|
||||
<TabsList role="tablist">
|
||||
{/* Arrow keys navigate, Space/Enter activates */}
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="password">Password</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="account">
|
||||
{/* Hidden unless selected, aria-labelledby links to trigger */}
|
||||
Account content
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
### Select
|
||||
|
||||
```tsx
|
||||
import { Select } from "@/components/ui/select"
|
||||
|
||||
<Select>
|
||||
<SelectTrigger aria-label="Choose theme">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{/* Keyboard navigable, announced to screen readers */}
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
```
|
||||
|
||||
### Checkbox and Radio
|
||||
|
||||
```tsx
|
||||
import { Checkbox } from "@/components/ui/checkbox"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox id="terms" aria-describedby="terms-description" />
|
||||
<Label htmlFor="terms">Accept terms</Label>
|
||||
</div>
|
||||
<p id="terms-description" className="text-sm text-muted-foreground">
|
||||
You agree to our Terms of Service and Privacy Policy
|
||||
</p>
|
||||
```
|
||||
|
||||
### Alert
|
||||
|
||||
```tsx
|
||||
import { Alert } from "@/components/ui/alert"
|
||||
|
||||
<Alert role="alert">
|
||||
{/* Announced immediately to screen readers */}
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>
|
||||
Your session has expired
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
```
|
||||
|
||||
## Color Contrast
|
||||
|
||||
Ensure sufficient contrast between text and background.
|
||||
|
||||
**WCAG Requirements:**
|
||||
- **AA**: 4.5:1 for normal text, 3:1 for large text
|
||||
- **AAA**: 7:1 for normal text, 4.5:1 for large text
|
||||
|
||||
**Check defaults:**
|
||||
```tsx
|
||||
// Good: High contrast
|
||||
<p className="text-gray-900 dark:text-gray-100">Text</p>
|
||||
|
||||
// Avoid: Low contrast
|
||||
<p className="text-gray-400 dark:text-gray-600">Hard to read</p>
|
||||
```
|
||||
|
||||
**Muted text:**
|
||||
```tsx
|
||||
// Use semantic muted foreground
|
||||
<p className="text-muted-foreground">
|
||||
Secondary text with accessible contrast
|
||||
</p>
|
||||
```
|
||||
|
||||
## Focus Indicators
|
||||
|
||||
Always provide visible focus indicators:
|
||||
|
||||
**Default focus ring:**
|
||||
```tsx
|
||||
<Button className="focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2">
|
||||
Button
|
||||
</Button>
|
||||
```
|
||||
|
||||
**Custom focus styles:**
|
||||
```tsx
|
||||
<a href="#" className="focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:underline">
|
||||
Link
|
||||
</a>
|
||||
```
|
||||
|
||||
**Don't remove focus styles:**
|
||||
```tsx
|
||||
// Avoid
|
||||
<button className="focus:outline-none">Bad</button>
|
||||
|
||||
// Use focus-visible instead
|
||||
<button className="focus-visible:ring-2">Good</button>
|
||||
```
|
||||
|
||||
## Motion and Animation
|
||||
|
||||
Respect reduced motion preference:
|
||||
|
||||
```css
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
* {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In components:
|
||||
```tsx
|
||||
<div className="transition-all motion-reduce:transition-none">
|
||||
Respects user preference
|
||||
</div>
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] All interactive elements keyboard accessible
|
||||
- [ ] Focus indicators visible
|
||||
- [ ] Screen reader announces all content correctly
|
||||
- [ ] Form errors announced and associated
|
||||
- [ ] Color contrast meets WCAG AA
|
||||
- [ ] Semantic HTML used
|
||||
- [ ] ARIA labels provided for icon-only buttons
|
||||
- [ ] Modal/dialog focus trap works
|
||||
- [ ] Dropdown/select keyboard navigable
|
||||
- [ ] Live regions announce updates
|
||||
- [ ] Respects reduced motion preference
|
||||
- [ ] Works with browser zoom up to 200%
|
||||
- [ ] Tab order logical
|
||||
- [ ] Skip links provided for navigation
|
||||
|
||||
## Tools
|
||||
|
||||
**Testing tools:**
|
||||
- Lighthouse accessibility audit
|
||||
- axe DevTools browser extension
|
||||
- NVDA/JAWS screen readers
|
||||
- Keyboard-only navigation testing
|
||||
- Color contrast checkers (Contrast Ratio, WebAIM)
|
||||
|
||||
**Automated testing:**
|
||||
```bash
|
||||
npm install -D @axe-core/react
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { useEffect } from 'react'
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
import('@axe-core/react').then((axe) => {
|
||||
axe.default(React, ReactDOM, 1000)
|
||||
})
|
||||
}
|
||||
```
|
||||
424
skills/ui-styling/references/shadcn-components.md
Normal file
424
skills/ui-styling/references/shadcn-components.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# shadcn/ui Component Reference
|
||||
|
||||
Complete catalog of shadcn/ui components with usage patterns and installation.
|
||||
|
||||
## Installation
|
||||
|
||||
**Add specific components:**
|
||||
```bash
|
||||
npx shadcn@latest add button
|
||||
npx shadcn@latest add button card dialog # Multiple
|
||||
npx shadcn@latest add --all # All components
|
||||
```
|
||||
|
||||
Components install to `components/ui/` with automatic dependency management.
|
||||
|
||||
## Form & Input Components
|
||||
|
||||
### Button
|
||||
```tsx
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
<Button variant="default">Default</Button>
|
||||
<Button variant="destructive">Delete</Button>
|
||||
<Button variant="outline" size="sm">Small Outline</Button>
|
||||
<Button variant="ghost" size="icon"><Icon /></Button>
|
||||
<Button variant="link">Link Style</Button>
|
||||
```
|
||||
|
||||
Variants: `default | destructive | outline | secondary | ghost | link`
|
||||
Sizes: `default | sm | lg | icon`
|
||||
|
||||
### Input
|
||||
```tsx
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email">Email</Label>
|
||||
<Input id="email" type="email" placeholder="you@example.com" />
|
||||
</div>
|
||||
```
|
||||
|
||||
### Form (with React Hook Form + Zod)
|
||||
```tsx
|
||||
import { useForm } from "react-hook-form"
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import * as z from "zod"
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
const schema = z.object({
|
||||
username: z.string().min(2).max(50),
|
||||
email: z.string().email()
|
||||
})
|
||||
|
||||
function ProfileForm() {
|
||||
const form = useForm({
|
||||
resolver: zodResolver(schema),
|
||||
defaultValues: { username: "", email: "" }
|
||||
})
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(console.log)} className="space-y-8">
|
||||
<FormField control={form.control} name="username" render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="shadcn" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)} />
|
||||
<Button type="submit">Submit</Button>
|
||||
</form>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Select
|
||||
```tsx
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
|
||||
<Select>
|
||||
<SelectTrigger className="w-[180px]">
|
||||
<SelectValue placeholder="Theme" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
<SelectItem value="system">System</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
```
|
||||
|
||||
### Checkbox
|
||||
```tsx
|
||||
import { Checkbox } from "@/components/ui/checkbox"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox id="terms" />
|
||||
<Label htmlFor="terms">Accept terms</Label>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Radio Group
|
||||
```tsx
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
<RadioGroup defaultValue="option-one">
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="option-one" id="option-one" />
|
||||
<Label htmlFor="option-one">Option One</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="option-two" id="option-two" />
|
||||
<Label htmlFor="option-two">Option Two</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
```
|
||||
|
||||
### Textarea
|
||||
```tsx
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
|
||||
<Textarea placeholder="Type your message here." />
|
||||
```
|
||||
|
||||
### Switch
|
||||
```tsx
|
||||
import { Switch } from "@/components/ui/switch"
|
||||
import { Label } from "@/components/ui/label"
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<Switch id="airplane-mode" />
|
||||
<Label htmlFor="airplane-mode">Airplane Mode</Label>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Date Picker
|
||||
```tsx
|
||||
import { Calendar } from "@/components/ui/calendar"
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { CalendarIcon } from "lucide-react"
|
||||
import { format } from "date-fns"
|
||||
import { useState } from "react"
|
||||
|
||||
const [date, setDate] = useState<Date>()
|
||||
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button variant="outline">
|
||||
<CalendarIcon className="mr-2 h-4 w-4" />
|
||||
{date ? format(date, "PPP") : "Pick a date"}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar mode="single" selected={date} onSelect={setDate} />
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
```
|
||||
|
||||
## Layout & Navigation
|
||||
|
||||
### Card
|
||||
```tsx
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Card Title</CardTitle>
|
||||
<CardDescription>Card Description</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p>Card Content</p>
|
||||
</CardContent>
|
||||
<CardFooter>
|
||||
<Button>Action</Button>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
```
|
||||
|
||||
### Tabs
|
||||
```tsx
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
|
||||
<Tabs defaultValue="account">
|
||||
<TabsList>
|
||||
<TabsTrigger value="account">Account</TabsTrigger>
|
||||
<TabsTrigger value="password">Password</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="account">Account settings</TabsContent>
|
||||
<TabsContent value="password">Password settings</TabsContent>
|
||||
</Tabs>
|
||||
```
|
||||
|
||||
### Accordion
|
||||
```tsx
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion"
|
||||
|
||||
<Accordion type="single" collapsible>
|
||||
<AccordionItem value="item-1">
|
||||
<AccordionTrigger>Is it accessible?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. It adheres to WAI-ARIA design pattern.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
<AccordionItem value="item-2">
|
||||
<AccordionTrigger>Is it styled?</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
Yes. Comes with default styles customizable with Tailwind.
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
### Navigation Menu
|
||||
```tsx
|
||||
import { NavigationMenu, NavigationMenuContent, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger } from "@/components/ui/navigation-menu"
|
||||
|
||||
<NavigationMenu>
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem>
|
||||
<NavigationMenuTrigger>Getting Started</NavigationMenuTrigger>
|
||||
<NavigationMenuContent>
|
||||
<NavigationMenuLink>Introduction</NavigationMenuLink>
|
||||
<NavigationMenuLink>Installation</NavigationMenuLink>
|
||||
</NavigationMenuContent>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
</NavigationMenu>
|
||||
```
|
||||
|
||||
## Overlays & Dialogs
|
||||
|
||||
### Dialog
|
||||
```tsx
|
||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
|
||||
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button>Open</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Are you sure?</DialogTitle>
|
||||
<DialogDescription>This action cannot be undone.</DialogDescription>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
```
|
||||
|
||||
### Drawer
|
||||
```tsx
|
||||
import { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from "@/components/ui/drawer"
|
||||
|
||||
<Drawer>
|
||||
<DrawerTrigger>Open</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerTitle>Title</DrawerTitle>
|
||||
<DrawerDescription>Description</DrawerDescription>
|
||||
</DrawerHeader>
|
||||
<DrawerFooter>
|
||||
<Button>Submit</Button>
|
||||
<DrawerClose>Cancel</DrawerClose>
|
||||
</DrawerFooter>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
```
|
||||
|
||||
### Popover
|
||||
```tsx
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
|
||||
|
||||
<Popover>
|
||||
<PopoverTrigger>Open</PopoverTrigger>
|
||||
<PopoverContent>Content here</PopoverContent>
|
||||
</Popover>
|
||||
```
|
||||
|
||||
### Toast
|
||||
```tsx
|
||||
import { useToast } from "@/hooks/use-toast"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
const { toast } = useToast()
|
||||
|
||||
<Button onClick={() => {
|
||||
toast({
|
||||
title: "Scheduled: Catch up",
|
||||
description: "Friday, February 10, 2023 at 5:57 PM"
|
||||
})
|
||||
}}>
|
||||
Show Toast
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Command
|
||||
```tsx
|
||||
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command"
|
||||
|
||||
<Command>
|
||||
<CommandInput placeholder="Type a command or search..." />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup heading="Suggestions">
|
||||
<CommandItem>Calendar</CommandItem>
|
||||
<CommandItem>Search Emoji</CommandItem>
|
||||
<CommandItem>Calculator</CommandItem>
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
```
|
||||
|
||||
### Alert Dialog
|
||||
```tsx
|
||||
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog"
|
||||
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>
|
||||
<Button variant="destructive">Delete</Button>
|
||||
</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Absolutely sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This permanently deletes your account and removes data from servers.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction>Continue</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
```
|
||||
|
||||
## Feedback & Status
|
||||
|
||||
### Alert
|
||||
```tsx
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
|
||||
<Alert>
|
||||
<AlertTitle>Heads up!</AlertTitle>
|
||||
<AlertDescription>You can add components using CLI.</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Alert variant="destructive">
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>Session expired. Please log in.</AlertDescription>
|
||||
</Alert>
|
||||
```
|
||||
|
||||
### Progress
|
||||
```tsx
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
|
||||
<Progress value={33} />
|
||||
```
|
||||
|
||||
### Skeleton
|
||||
```tsx
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
<Skeleton className="h-12 w-12 rounded-full" />
|
||||
<div className="space-y-2">
|
||||
<Skeleton className="h-4 w-[250px]" />
|
||||
<Skeleton className="h-4 w-[200px]" />
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Display Components
|
||||
|
||||
### Table
|
||||
```tsx
|
||||
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
|
||||
|
||||
<Table>
|
||||
<TableCaption>Recent invoices</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Invoice</TableHead>
|
||||
<TableHead>Status</TableHead>
|
||||
<TableHead>Amount</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>INV001</TableCell>
|
||||
<TableCell>Paid</TableCell>
|
||||
<TableCell>$250.00</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
```
|
||||
|
||||
### Avatar
|
||||
```tsx
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
|
||||
<Avatar>
|
||||
<AvatarImage src="https://github.com/shadcn.png" />
|
||||
<AvatarFallback>CN</AvatarFallback>
|
||||
</Avatar>
|
||||
```
|
||||
|
||||
### Badge
|
||||
```tsx
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
|
||||
<Badge>Default</Badge>
|
||||
<Badge variant="secondary">Secondary</Badge>
|
||||
<Badge variant="destructive">Destructive</Badge>
|
||||
<Badge variant="outline">Outline</Badge>
|
||||
```
|
||||
373
skills/ui-styling/references/shadcn-theming.md
Normal file
373
skills/ui-styling/references/shadcn-theming.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# shadcn/ui Theming & Customization
|
||||
|
||||
Theme configuration, CSS variables, dark mode, and component customization.
|
||||
|
||||
## Dark Mode Setup
|
||||
|
||||
### Next.js App Router
|
||||
|
||||
**1. Install next-themes:**
|
||||
```bash
|
||||
npm install next-themes
|
||||
```
|
||||
|
||||
**2. Create theme provider:**
|
||||
```tsx
|
||||
// components/theme-provider.tsx
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes"
|
||||
|
||||
export function ThemeProvider({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof NextThemesProvider>) {
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
||||
}
|
||||
```
|
||||
|
||||
**3. Wrap app:**
|
||||
```tsx
|
||||
// app/layout.tsx
|
||||
import { ThemeProvider } from "@/components/theme-provider"
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body>
|
||||
<ThemeProvider
|
||||
attribute="class"
|
||||
defaultTheme="system"
|
||||
enableSystem
|
||||
disableTransitionOnChange
|
||||
>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
**4. Theme toggle component:**
|
||||
```tsx
|
||||
import { Moon, Sun } from "lucide-react"
|
||||
import { useTheme } from "next-themes"
|
||||
import { Button } from "@/components/ui/button"
|
||||
|
||||
export function ThemeToggle() {
|
||||
const { setTheme, theme } = useTheme()
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => setTheme(theme === "light" ? "dark" : "light")}
|
||||
>
|
||||
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
|
||||
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
|
||||
<span className="sr-only">Toggle theme</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
### Vite / Other Frameworks
|
||||
|
||||
Use similar approach with next-themes or implement custom solution:
|
||||
|
||||
```javascript
|
||||
// Store preference
|
||||
function toggleDarkMode() {
|
||||
const isDark = document.documentElement.classList.toggle('dark')
|
||||
localStorage.setItem('theme', isDark ? 'dark' : 'light')
|
||||
}
|
||||
|
||||
// Initialize on load
|
||||
if (localStorage.theme === 'dark' ||
|
||||
(!('theme' in localStorage) &&
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
||||
document.documentElement.classList.add('dark')
|
||||
}
|
||||
```
|
||||
|
||||
## CSS Variable System
|
||||
|
||||
shadcn/ui uses CSS variables for theming. Variables defined in `globals.css`:
|
||||
|
||||
```css
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 222.2 84% 4.9%;
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Color Format
|
||||
|
||||
Values use HSL format without `hsl()` wrapper for better opacity control:
|
||||
```css
|
||||
--primary: 222.2 47.4% 11.2%; /* H S L */
|
||||
```
|
||||
|
||||
Usage in Tailwind:
|
||||
```css
|
||||
background: hsl(var(--primary));
|
||||
background: hsl(var(--primary) / 0.5); /* 50% opacity */
|
||||
```
|
||||
|
||||
## Tailwind Configuration
|
||||
|
||||
Map CSS variables to Tailwind utilities:
|
||||
|
||||
```ts
|
||||
// tailwind.config.ts
|
||||
export default {
|
||||
darkMode: ["class"],
|
||||
theme: {
|
||||
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))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive))",
|
||||
foreground: "hsl(var(--destructive-foreground))",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: "var(--radius)",
|
||||
md: "calc(var(--radius) - 2px)",
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Color Customization
|
||||
|
||||
### Method 1: Update CSS Variables
|
||||
|
||||
Change colors by modifying CSS variables in `globals.css`:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--primary: 262.1 83.3% 57.8%; /* Purple */
|
||||
--primary-foreground: 210 20% 98%;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--primary: 263.4 70% 50.4%; /* Darker purple */
|
||||
--primary-foreground: 210 20% 98%;
|
||||
}
|
||||
```
|
||||
|
||||
### Method 2: Theme Generator
|
||||
|
||||
Use shadcn/ui theme generator: https://ui.shadcn.com/themes
|
||||
|
||||
Select base color, generate theme, copy CSS variables.
|
||||
|
||||
### Method 3: Multiple Themes
|
||||
|
||||
Create theme variants with data attributes:
|
||||
|
||||
```css
|
||||
[data-theme="violet"] {
|
||||
--primary: 262.1 83.3% 57.8%;
|
||||
--primary-foreground: 210 20% 98%;
|
||||
}
|
||||
|
||||
[data-theme="rose"] {
|
||||
--primary: 346.8 77.2% 49.8%;
|
||||
--primary-foreground: 355.7 100% 97.3%;
|
||||
}
|
||||
```
|
||||
|
||||
Apply theme:
|
||||
```tsx
|
||||
<div data-theme="violet">
|
||||
<Button>Violet theme</Button>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Component Customization
|
||||
|
||||
Components live in your codebase - modify directly.
|
||||
|
||||
### Customize Variants
|
||||
|
||||
```tsx
|
||||
// components/ui/button.tsx
|
||||
const buttonVariants = cva(
|
||||
"inline-flex items-center justify-center rounded-md text-sm font-medium",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary text-primary-foreground",
|
||||
destructive: "bg-destructive text-destructive-foreground",
|
||||
outline: "border border-input bg-background",
|
||||
// Add custom variant
|
||||
gradient: "bg-gradient-to-r from-purple-500 to-pink-500 text-white",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2",
|
||||
sm: "h-9 rounded-md px-3",
|
||||
lg: "h-11 rounded-md px-8",
|
||||
// Add custom size
|
||||
xl: "h-14 rounded-md px-10 text-lg",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
size: "default",
|
||||
},
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Usage:
|
||||
```tsx
|
||||
<Button variant="gradient" size="xl">Custom Button</Button>
|
||||
```
|
||||
|
||||
### Customize Styles
|
||||
|
||||
Modify base styles in component:
|
||||
|
||||
```tsx
|
||||
// components/ui/card.tsx
|
||||
const Card = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"rounded-xl border bg-card text-card-foreground shadow-lg", // Modified
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
))
|
||||
```
|
||||
|
||||
### Override with className
|
||||
|
||||
Pass additional classes to override:
|
||||
|
||||
```tsx
|
||||
<Card className="border-2 border-purple-500 shadow-2xl hover:scale-105 transition-transform">
|
||||
Custom styled card
|
||||
</Card>
|
||||
```
|
||||
|
||||
## Base Color Presets
|
||||
|
||||
shadcn/ui provides base color presets during `init`:
|
||||
|
||||
- **Slate**: Cool gray tones
|
||||
- **Gray**: Neutral gray
|
||||
- **Zinc**: Warm gray
|
||||
- **Neutral**: Balanced gray
|
||||
- **Stone**: Earthy gray
|
||||
|
||||
Select during setup or change later by updating CSS variables.
|
||||
|
||||
## Style Variants
|
||||
|
||||
Two component styles available:
|
||||
|
||||
- **Default**: Softer, more rounded
|
||||
- **New York**: Sharp, more contrast
|
||||
|
||||
Select during `init` or in `components.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"style": "new-york",
|
||||
"tailwind": {
|
||||
"cssVariables": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Radius Customization
|
||||
|
||||
Control border radius globally:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--radius: 0.5rem; /* Default */
|
||||
--radius: 0rem; /* Sharp corners */
|
||||
--radius: 1rem; /* Rounded */
|
||||
}
|
||||
```
|
||||
|
||||
Components use radius variable:
|
||||
```tsx
|
||||
className="rounded-lg" /* Uses var(--radius) */
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use CSS Variables**: Enables runtime theme switching
|
||||
2. **Consistent Foreground Colors**: Pair each color with appropriate foreground
|
||||
3. **Test Both Themes**: Verify components in light and dark modes
|
||||
4. **Semantic Naming**: Use `destructive` not `red`, `muted` not `gray`
|
||||
5. **Accessibility**: Maintain sufficient color contrast (WCAG AA minimum)
|
||||
6. **Component Overrides**: Use `className` prop for one-off customization
|
||||
7. **Extract Patterns**: Create custom variants for repeated customizations
|
||||
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)
|
||||
382
skills/ui-styling/references/tailwind-responsive.md
Normal file
382
skills/ui-styling/references/tailwind-responsive.md
Normal file
@@ -0,0 +1,382 @@
|
||||
# Tailwind CSS Responsive Design
|
||||
|
||||
Mobile-first breakpoints, responsive utilities, and adaptive layouts.
|
||||
|
||||
## Mobile-First Approach
|
||||
|
||||
Tailwind uses mobile-first responsive design. Base styles apply to all screen sizes, then use breakpoint prefixes to override at larger sizes.
|
||||
|
||||
```html
|
||||
<!-- Base: 1 column (mobile)
|
||||
sm: 2 columns (tablet)
|
||||
lg: 4 columns (desktop) -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
|
||||
<div>Item 1</div>
|
||||
<div>Item 2</div>
|
||||
<div>Item 3</div>
|
||||
<div>Item 4</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Breakpoint System
|
||||
|
||||
**Default breakpoints:**
|
||||
|
||||
| Prefix | Min Width | CSS Media Query |
|
||||
|--------|-----------|-----------------|
|
||||
| `sm:` | 640px | `@media (min-width: 640px)` |
|
||||
| `md:` | 768px | `@media (min-width: 768px)` |
|
||||
| `lg:` | 1024px | `@media (min-width: 1024px)` |
|
||||
| `xl:` | 1280px | `@media (min-width: 1280px)` |
|
||||
| `2xl:` | 1536px | `@media (min-width: 1536px)` |
|
||||
|
||||
## Responsive Patterns
|
||||
|
||||
### Layout Changes
|
||||
|
||||
```html
|
||||
<!-- Vertical on mobile, horizontal on desktop -->
|
||||
<div class="flex flex-col lg:flex-row gap-4">
|
||||
<div>Left</div>
|
||||
<div>Right</div>
|
||||
</div>
|
||||
|
||||
<!-- 1 column -> 2 columns -> 3 columns -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||||
<div>Item 1</div>
|
||||
<div>Item 2</div>
|
||||
<div>Item 3</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Visibility
|
||||
|
||||
```html
|
||||
<!-- Hide on mobile, show on desktop -->
|
||||
<div class="hidden lg:block">
|
||||
Desktop only content
|
||||
</div>
|
||||
|
||||
<!-- Show on mobile, hide on desktop -->
|
||||
<div class="block lg:hidden">
|
||||
Mobile only content
|
||||
</div>
|
||||
|
||||
<!-- Different content per breakpoint -->
|
||||
<div class="lg:hidden">Mobile menu</div>
|
||||
<div class="hidden lg:flex">Desktop navigation</div>
|
||||
```
|
||||
|
||||
### Typography
|
||||
|
||||
```html
|
||||
<!-- Responsive text sizes -->
|
||||
<h1 class="text-2xl md:text-4xl lg:text-6xl font-bold">
|
||||
Heading scales with screen size
|
||||
</h1>
|
||||
|
||||
<p class="text-sm md:text-base lg:text-lg">
|
||||
Body text scales appropriately
|
||||
</p>
|
||||
```
|
||||
|
||||
### Spacing
|
||||
|
||||
```html
|
||||
<!-- Responsive padding -->
|
||||
<div class="p-4 md:p-6 lg:p-8">
|
||||
More padding on larger screens
|
||||
</div>
|
||||
|
||||
<!-- Responsive gap -->
|
||||
<div class="flex gap-2 md:gap-4 lg:gap-6">
|
||||
<div>Item 1</div>
|
||||
<div>Item 2</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Width
|
||||
|
||||
```html
|
||||
<!-- Full width on mobile, constrained on desktop -->
|
||||
<div class="w-full lg:w-1/2 xl:w-1/3">
|
||||
Responsive width
|
||||
</div>
|
||||
|
||||
<!-- Responsive max-width -->
|
||||
<div class="max-w-sm md:max-w-2xl lg:max-w-4xl mx-auto">
|
||||
Centered with responsive max width
|
||||
</div>
|
||||
```
|
||||
|
||||
## Common Responsive Layouts
|
||||
|
||||
### Sidebar Layout
|
||||
|
||||
```html
|
||||
<div class="flex flex-col lg:flex-row min-h-screen">
|
||||
<!-- Sidebar: Full width on mobile, fixed on desktop -->
|
||||
<aside class="w-full lg:w-64 bg-gray-100 p-4">
|
||||
Sidebar
|
||||
</aside>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="flex-1 p-4 md:p-8">
|
||||
Main content
|
||||
</main>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Card Grid
|
||||
|
||||
```html
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 md:gap-6">
|
||||
<div class="bg-white rounded-lg shadow p-6">Card 1</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">Card 2</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">Card 3</div>
|
||||
<div class="bg-white rounded-lg shadow p-6">Card 4</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Hero Section
|
||||
|
||||
```html
|
||||
<section class="py-12 md:py-20 lg:py-32">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex flex-col lg:flex-row items-center gap-8 lg:gap-12">
|
||||
<div class="flex-1 text-center lg:text-left">
|
||||
<h1 class="text-4xl md:text-5xl lg:text-6xl font-bold mb-4">
|
||||
Hero Title
|
||||
</h1>
|
||||
<p class="text-lg md:text-xl mb-6">
|
||||
Hero description
|
||||
</p>
|
||||
<button class="px-6 py-3 md:px-8 md:py-4">
|
||||
CTA Button
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<img src="hero.jpg" class="w-full rounded-lg" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
### Navigation
|
||||
|
||||
```html
|
||||
<nav class="bg-white shadow">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<div class="text-xl font-bold">Logo</div>
|
||||
|
||||
<!-- Desktop navigation -->
|
||||
<div class="hidden md:flex gap-6">
|
||||
<a href="#">Home</a>
|
||||
<a href="#">About</a>
|
||||
<a href="#">Services</a>
|
||||
<a href="#">Contact</a>
|
||||
</div>
|
||||
|
||||
<!-- Mobile menu button -->
|
||||
<button class="md:hidden">
|
||||
<svg class="w-6 h-6">...</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
```
|
||||
|
||||
## Max-Width Queries
|
||||
|
||||
Apply styles only below certain breakpoint using `max-*:` prefix:
|
||||
|
||||
```html
|
||||
<!-- Only on mobile and tablet (below 1024px) -->
|
||||
<div class="max-lg:text-center">
|
||||
Centered on mobile/tablet, left-aligned on desktop
|
||||
</div>
|
||||
|
||||
<!-- Only on mobile (below 640px) -->
|
||||
<div class="max-sm:hidden">
|
||||
Hidden only on mobile
|
||||
</div>
|
||||
```
|
||||
|
||||
Available: `max-sm:` `max-md:` `max-lg:` `max-xl:` `max-2xl:`
|
||||
|
||||
## Range Queries
|
||||
|
||||
Apply styles between breakpoints:
|
||||
|
||||
```html
|
||||
<!-- Only on tablets (between md and lg) -->
|
||||
<div class="md:block lg:hidden">
|
||||
Visible only on tablets
|
||||
</div>
|
||||
|
||||
<!-- Between sm and xl -->
|
||||
<div class="sm:grid-cols-2 xl:grid-cols-4">
|
||||
2 columns on tablet, 4 on extra large
|
||||
</div>
|
||||
```
|
||||
|
||||
## Container Queries
|
||||
|
||||
Style elements based on parent container width:
|
||||
|
||||
```html
|
||||
<div class="@container">
|
||||
<div class="@md:grid-cols-2 @lg:grid-cols-3">
|
||||
Responds to parent width, not viewport
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Container query breakpoints: `@sm:` `@md:` `@lg:` `@xl:` `@2xl:`
|
||||
|
||||
## Custom Breakpoints
|
||||
|
||||
Define custom breakpoints in theme:
|
||||
|
||||
```css
|
||||
@theme {
|
||||
--breakpoint-3xl: 120rem; /* 1920px */
|
||||
--breakpoint-tablet: 48rem; /* 768px */
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div class="tablet:grid-cols-2 3xl:grid-cols-6">
|
||||
Uses custom breakpoints
|
||||
</div>
|
||||
```
|
||||
|
||||
## Responsive State Variants
|
||||
|
||||
Combine responsive with hover/focus:
|
||||
|
||||
```html
|
||||
<!-- Hover effect only on desktop -->
|
||||
<button class="lg:hover:scale-105">
|
||||
Scale on hover (desktop only)
|
||||
</button>
|
||||
|
||||
<!-- Different hover colors per breakpoint -->
|
||||
<a class="hover:text-blue-600 lg:hover:text-purple-600">
|
||||
Link
|
||||
</a>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Mobile-First Design
|
||||
|
||||
Start with mobile styles, add complexity at larger breakpoints:
|
||||
|
||||
```html
|
||||
<!-- Good: Mobile first -->
|
||||
<div class="text-base md:text-lg lg:text-xl">
|
||||
|
||||
<!-- Avoid: Desktop first -->
|
||||
<div class="text-xl lg:text-base">
|
||||
```
|
||||
|
||||
### 2. Consistent Breakpoint Usage
|
||||
|
||||
Use same breakpoints across related elements:
|
||||
|
||||
```html
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6 lg:gap-8">
|
||||
Spacing scales with layout
|
||||
</div>
|
||||
```
|
||||
|
||||
### 3. Test at Breakpoint Boundaries
|
||||
|
||||
Test at exact breakpoint widths (640px, 768px, 1024px, etc.) to catch edge cases.
|
||||
|
||||
### 4. Use Container for Content Width
|
||||
|
||||
```html
|
||||
<div class="container mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl">
|
||||
Content with consistent max width
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 5. Progressive Enhancement
|
||||
|
||||
Ensure core functionality works on mobile, enhance for larger screens:
|
||||
|
||||
```html
|
||||
<!-- Core layout works on mobile -->
|
||||
<div class="p-4">
|
||||
<!-- Enhanced spacing on desktop -->
|
||||
<div class="lg:p-8">
|
||||
Content
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 6. Avoid Too Many Breakpoints
|
||||
|
||||
Use 2-3 breakpoints per element for maintainability:
|
||||
|
||||
```html
|
||||
<!-- Good: 2 breakpoints -->
|
||||
<div class="grid-cols-1 md:grid-cols-2 lg:grid-cols-4">
|
||||
|
||||
<!-- Avoid: Too many breakpoints -->
|
||||
<div class="grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6">
|
||||
```
|
||||
|
||||
## Common Responsive Utilities
|
||||
|
||||
### Responsive Display
|
||||
|
||||
```html
|
||||
<div class="block md:flex lg:grid">
|
||||
Changes display type per breakpoint
|
||||
</div>
|
||||
```
|
||||
|
||||
### Responsive Position
|
||||
|
||||
```html
|
||||
<div class="relative lg:absolute">
|
||||
Positioned differently per breakpoint
|
||||
</div>
|
||||
```
|
||||
|
||||
### Responsive Order
|
||||
|
||||
```html
|
||||
<div class="flex flex-col">
|
||||
<div class="order-2 lg:order-1">First on desktop</div>
|
||||
<div class="order-1 lg:order-2">First on mobile</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Responsive Overflow
|
||||
|
||||
```html
|
||||
<div class="overflow-auto lg:overflow-visible">
|
||||
Scrollable on mobile, expanded on desktop
|
||||
</div>
|
||||
```
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Test at 320px (small mobile)
|
||||
- [ ] Test at 640px (mobile breakpoint)
|
||||
- [ ] Test at 768px (tablet breakpoint)
|
||||
- [ ] Test at 1024px (desktop breakpoint)
|
||||
- [ ] Test at 1280px (large desktop breakpoint)
|
||||
- [ ] Test landscape orientation
|
||||
- [ ] Verify touch targets (min 44x44px)
|
||||
- [ ] Check text readability at all sizes
|
||||
- [ ] Verify navigation works on mobile
|
||||
- [ ] Test with browser zoom
|
||||
455
skills/ui-styling/references/tailwind-utilities.md
Normal file
455
skills/ui-styling/references/tailwind-utilities.md
Normal file
@@ -0,0 +1,455 @@
|
||||
# Tailwind CSS Utility Reference
|
||||
|
||||
Core utility classes for layout, spacing, typography, colors, borders, and shadows.
|
||||
|
||||
## Layout Utilities
|
||||
|
||||
### Display
|
||||
|
||||
```html
|
||||
<div class="block">Block</div>
|
||||
<div class="inline-block">Inline Block</div>
|
||||
<div class="inline">Inline</div>
|
||||
<div class="flex">Flexbox</div>
|
||||
<div class="inline-flex">Inline Flex</div>
|
||||
<div class="grid">Grid</div>
|
||||
<div class="inline-grid">Inline Grid</div>
|
||||
<div class="hidden">Hidden</div>
|
||||
```
|
||||
|
||||
### Flexbox
|
||||
|
||||
**Container:**
|
||||
```html
|
||||
<div class="flex flex-row">Row (default)</div>
|
||||
<div class="flex flex-col">Column</div>
|
||||
<div class="flex flex-row-reverse">Reverse row</div>
|
||||
<div class="flex flex-col-reverse">Reverse column</div>
|
||||
```
|
||||
|
||||
**Justify (main axis):**
|
||||
```html
|
||||
<div class="flex justify-start">Start</div>
|
||||
<div class="flex justify-center">Center</div>
|
||||
<div class="flex justify-end">End</div>
|
||||
<div class="flex justify-between">Space between</div>
|
||||
<div class="flex justify-around">Space around</div>
|
||||
<div class="flex justify-evenly">Space evenly</div>
|
||||
```
|
||||
|
||||
**Align (cross axis):**
|
||||
```html
|
||||
<div class="flex items-start">Start</div>
|
||||
<div class="flex items-center">Center</div>
|
||||
<div class="flex items-end">End</div>
|
||||
<div class="flex items-baseline">Baseline</div>
|
||||
<div class="flex items-stretch">Stretch</div>
|
||||
```
|
||||
|
||||
**Gap:**
|
||||
```html
|
||||
<div class="flex gap-4">All sides</div>
|
||||
<div class="flex gap-x-6 gap-y-2">X and Y</div>
|
||||
```
|
||||
|
||||
**Wrap:**
|
||||
```html
|
||||
<div class="flex flex-wrap">Wrap</div>
|
||||
<div class="flex flex-nowrap">No wrap</div>
|
||||
```
|
||||
|
||||
### Grid
|
||||
|
||||
**Columns:**
|
||||
```html
|
||||
<div class="grid grid-cols-1">1 column</div>
|
||||
<div class="grid grid-cols-2">2 columns</div>
|
||||
<div class="grid grid-cols-3">3 columns</div>
|
||||
<div class="grid grid-cols-4">4 columns</div>
|
||||
<div class="grid grid-cols-12">12 columns</div>
|
||||
<div class="grid grid-cols-[1fr_500px_2fr]">Custom</div>
|
||||
```
|
||||
|
||||
**Rows:**
|
||||
```html
|
||||
<div class="grid grid-rows-3">3 rows</div>
|
||||
<div class="grid grid-rows-[auto_1fr_auto]">Custom</div>
|
||||
```
|
||||
|
||||
**Span:**
|
||||
```html
|
||||
<div class="col-span-2">Span 2 columns</div>
|
||||
<div class="row-span-3">Span 3 rows</div>
|
||||
```
|
||||
|
||||
**Gap:**
|
||||
```html
|
||||
<div class="grid gap-4">All sides</div>
|
||||
<div class="grid gap-x-8 gap-y-4">X and Y</div>
|
||||
```
|
||||
|
||||
### Positioning
|
||||
|
||||
```html
|
||||
<div class="static">Static (default)</div>
|
||||
<div class="relative">Relative</div>
|
||||
<div class="absolute">Absolute</div>
|
||||
<div class="fixed">Fixed</div>
|
||||
<div class="sticky">Sticky</div>
|
||||
|
||||
<!-- Position values -->
|
||||
<div class="absolute top-0 right-0">Top right</div>
|
||||
<div class="absolute inset-0">All sides 0</div>
|
||||
<div class="absolute inset-x-4">Left/right 4</div>
|
||||
<div class="absolute inset-y-8">Top/bottom 8</div>
|
||||
```
|
||||
|
||||
### Z-Index
|
||||
|
||||
```html
|
||||
<div class="z-0">z-index: 0</div>
|
||||
<div class="z-10">z-index: 10</div>
|
||||
<div class="z-20">z-index: 20</div>
|
||||
<div class="z-50">z-index: 50</div>
|
||||
```
|
||||
|
||||
## Spacing Utilities
|
||||
|
||||
### Padding
|
||||
|
||||
```html
|
||||
<div class="p-4">All sides</div>
|
||||
<div class="px-6">Left and right</div>
|
||||
<div class="py-3">Top and bottom</div>
|
||||
<div class="pt-8">Top</div>
|
||||
<div class="pr-4">Right</div>
|
||||
<div class="pb-2">Bottom</div>
|
||||
<div class="pl-6">Left</div>
|
||||
```
|
||||
|
||||
### Margin
|
||||
|
||||
```html
|
||||
<div class="m-4">All sides</div>
|
||||
<div class="mx-auto">Center horizontally</div>
|
||||
<div class="my-6">Top and bottom</div>
|
||||
<div class="mt-8">Top</div>
|
||||
<div class="-mt-4">Negative top</div>
|
||||
<div class="ml-auto">Push to right</div>
|
||||
```
|
||||
|
||||
### Space Between
|
||||
|
||||
```html
|
||||
<div class="space-x-4">Horizontal spacing</div>
|
||||
<div class="space-y-6">Vertical spacing</div>
|
||||
```
|
||||
|
||||
### Spacing Scale
|
||||
|
||||
- `0`: 0px
|
||||
- `px`: 1px
|
||||
- `0.5`: 0.125rem (2px)
|
||||
- `1`: 0.25rem (4px)
|
||||
- `2`: 0.5rem (8px)
|
||||
- `3`: 0.75rem (12px)
|
||||
- `4`: 1rem (16px)
|
||||
- `6`: 1.5rem (24px)
|
||||
- `8`: 2rem (32px)
|
||||
- `12`: 3rem (48px)
|
||||
- `16`: 4rem (64px)
|
||||
- `24`: 6rem (96px)
|
||||
|
||||
## Typography
|
||||
|
||||
### Font Size
|
||||
|
||||
```html
|
||||
<p class="text-xs">Extra small (12px)</p>
|
||||
<p class="text-sm">Small (14px)</p>
|
||||
<p class="text-base">Base (16px)</p>
|
||||
<p class="text-lg">Large (18px)</p>
|
||||
<p class="text-xl">XL (20px)</p>
|
||||
<p class="text-2xl">2XL (24px)</p>
|
||||
<p class="text-3xl">3XL (30px)</p>
|
||||
<p class="text-4xl">4XL (36px)</p>
|
||||
<p class="text-5xl">5XL (48px)</p>
|
||||
```
|
||||
|
||||
### Font Weight
|
||||
|
||||
```html
|
||||
<p class="font-thin">Thin (100)</p>
|
||||
<p class="font-light">Light (300)</p>
|
||||
<p class="font-normal">Normal (400)</p>
|
||||
<p class="font-medium">Medium (500)</p>
|
||||
<p class="font-semibold">Semibold (600)</p>
|
||||
<p class="font-bold">Bold (700)</p>
|
||||
<p class="font-black">Black (900)</p>
|
||||
```
|
||||
|
||||
### Text Alignment
|
||||
|
||||
```html
|
||||
<p class="text-left">Left</p>
|
||||
<p class="text-center">Center</p>
|
||||
<p class="text-right">Right</p>
|
||||
<p class="text-justify">Justify</p>
|
||||
```
|
||||
|
||||
### Line Height
|
||||
|
||||
```html
|
||||
<p class="leading-none">1</p>
|
||||
<p class="leading-tight">1.25</p>
|
||||
<p class="leading-normal">1.5</p>
|
||||
<p class="leading-relaxed">1.75</p>
|
||||
<p class="leading-loose">2</p>
|
||||
```
|
||||
|
||||
### Combined Font Utilities
|
||||
|
||||
```html
|
||||
<h1 class="text-4xl/tight font-bold">
|
||||
Font size 4xl with tight line height
|
||||
</h1>
|
||||
```
|
||||
|
||||
### Text Transform
|
||||
|
||||
```html
|
||||
<p class="uppercase">UPPERCASE</p>
|
||||
<p class="lowercase">lowercase</p>
|
||||
<p class="capitalize">Capitalize</p>
|
||||
<p class="normal-case">Normal</p>
|
||||
```
|
||||
|
||||
### Text Decoration
|
||||
|
||||
```html
|
||||
<p class="underline">Underline</p>
|
||||
<p class="line-through">Line through</p>
|
||||
<p class="no-underline">No underline</p>
|
||||
```
|
||||
|
||||
### Text Overflow
|
||||
|
||||
```html
|
||||
<p class="truncate">Truncate with ellipsis...</p>
|
||||
<p class="line-clamp-3">Clamp to 3 lines...</p>
|
||||
<p class="text-ellipsis overflow-hidden">Ellipsis</p>
|
||||
```
|
||||
|
||||
## Colors
|
||||
|
||||
### Text Colors
|
||||
|
||||
```html
|
||||
<p class="text-black">Black</p>
|
||||
<p class="text-white">White</p>
|
||||
<p class="text-gray-500">Gray 500</p>
|
||||
<p class="text-red-600">Red 600</p>
|
||||
<p class="text-blue-500">Blue 500</p>
|
||||
<p class="text-green-600">Green 600</p>
|
||||
```
|
||||
|
||||
### Background Colors
|
||||
|
||||
```html
|
||||
<div class="bg-white">White</div>
|
||||
<div class="bg-gray-100">Gray 100</div>
|
||||
<div class="bg-blue-500">Blue 500</div>
|
||||
<div class="bg-red-600">Red 600</div>
|
||||
```
|
||||
|
||||
### Color Scale
|
||||
|
||||
Each color has 11 shades (50-950):
|
||||
- `50`: Lightest
|
||||
- `100-400`: Light variations
|
||||
- `500`: Base color
|
||||
- `600-800`: Dark variations
|
||||
- `950`: Darkest
|
||||
|
||||
### Opacity Modifiers
|
||||
|
||||
```html
|
||||
<div class="bg-black/75">75% opacity</div>
|
||||
<div class="text-blue-500/30">30% opacity</div>
|
||||
<div class="bg-purple-500/[0.87]">87% opacity</div>
|
||||
```
|
||||
|
||||
### Gradients
|
||||
|
||||
```html
|
||||
<div class="bg-gradient-to-r from-blue-500 to-purple-600">
|
||||
Left to right gradient
|
||||
</div>
|
||||
<div class="bg-gradient-to-br from-pink-500 via-red-500 to-yellow-500">
|
||||
With via color
|
||||
</div>
|
||||
```
|
||||
|
||||
Directions: `to-t | to-tr | to-r | to-br | to-b | to-bl | to-l | to-tl`
|
||||
|
||||
## Borders
|
||||
|
||||
### Border Width
|
||||
|
||||
```html
|
||||
<div class="border">1px all sides</div>
|
||||
<div class="border-2">2px all sides</div>
|
||||
<div class="border-t">Top only</div>
|
||||
<div class="border-r-4">Right 4px</div>
|
||||
<div class="border-b-2">Bottom 2px</div>
|
||||
<div class="border-l">Left only</div>
|
||||
<div class="border-0">No border</div>
|
||||
```
|
||||
|
||||
### Border Color
|
||||
|
||||
```html
|
||||
<div class="border border-gray-300">Gray</div>
|
||||
<div class="border-2 border-blue-500">Blue</div>
|
||||
<div class="border border-red-600/50">Red with opacity</div>
|
||||
```
|
||||
|
||||
### Border Radius
|
||||
|
||||
```html
|
||||
<div class="rounded">0.25rem</div>
|
||||
<div class="rounded-md">0.375rem</div>
|
||||
<div class="rounded-lg">0.5rem</div>
|
||||
<div class="rounded-xl">0.75rem</div>
|
||||
<div class="rounded-2xl">1rem</div>
|
||||
<div class="rounded-full">9999px</div>
|
||||
|
||||
<!-- Individual corners -->
|
||||
<div class="rounded-t-lg">Top corners</div>
|
||||
<div class="rounded-br-xl">Bottom right</div>
|
||||
```
|
||||
|
||||
### Border Style
|
||||
|
||||
```html
|
||||
<div class="border border-solid">Solid</div>
|
||||
<div class="border-2 border-dashed">Dashed</div>
|
||||
<div class="border border-dotted">Dotted</div>
|
||||
```
|
||||
|
||||
## Shadows
|
||||
|
||||
```html
|
||||
<div class="shadow-sm">Small</div>
|
||||
<div class="shadow">Default</div>
|
||||
<div class="shadow-md">Medium</div>
|
||||
<div class="shadow-lg">Large</div>
|
||||
<div class="shadow-xl">Extra large</div>
|
||||
<div class="shadow-2xl">2XL</div>
|
||||
<div class="shadow-none">No shadow</div>
|
||||
```
|
||||
|
||||
### Colored Shadows
|
||||
|
||||
```html
|
||||
<div class="shadow-lg shadow-blue-500/50">Blue shadow</div>
|
||||
```
|
||||
|
||||
## Width & Height
|
||||
|
||||
### Width
|
||||
|
||||
```html
|
||||
<div class="w-full">100%</div>
|
||||
<div class="w-1/2">50%</div>
|
||||
<div class="w-1/3">33.333%</div>
|
||||
<div class="w-64">16rem</div>
|
||||
<div class="w-[500px]">500px</div>
|
||||
<div class="w-screen">100vw</div>
|
||||
|
||||
<!-- Min/Max width -->
|
||||
<div class="min-w-0">min-width: 0</div>
|
||||
<div class="max-w-md">max-width: 28rem</div>
|
||||
<div class="max-w-screen-xl">max-width: 1280px</div>
|
||||
```
|
||||
|
||||
### Height
|
||||
|
||||
```html
|
||||
<div class="h-full">100%</div>
|
||||
<div class="h-screen">100vh</div>
|
||||
<div class="h-64">16rem</div>
|
||||
<div class="h-[500px]">500px</div>
|
||||
|
||||
<!-- Min/Max height -->
|
||||
<div class="min-h-screen">min-height: 100vh</div>
|
||||
<div class="max-h-96">max-height: 24rem</div>
|
||||
```
|
||||
|
||||
## Arbitrary Values
|
||||
|
||||
Use square brackets for custom values:
|
||||
|
||||
```html
|
||||
<!-- Spacing -->
|
||||
<div class="p-[17px]">Custom padding</div>
|
||||
<div class="top-[117px]">Custom position</div>
|
||||
|
||||
<!-- Colors -->
|
||||
<div class="bg-[#bada55]">Hex color</div>
|
||||
<div class="text-[rgb(123,45,67)]">RGB</div>
|
||||
|
||||
<!-- Sizes -->
|
||||
<div class="w-[500px]">Custom width</div>
|
||||
<div class="text-[22px]">Custom font size</div>
|
||||
|
||||
<!-- CSS variables -->
|
||||
<div class="bg-[var(--brand-color)]">CSS var</div>
|
||||
|
||||
<!-- Complex values -->
|
||||
<div class="grid-cols-[1fr_500px_2fr]">Custom grid</div>
|
||||
```
|
||||
|
||||
## Aspect Ratio
|
||||
|
||||
```html
|
||||
<div class="aspect-square">1:1</div>
|
||||
<div class="aspect-video">16:9</div>
|
||||
<div class="aspect-[4/3]">4:3</div>
|
||||
```
|
||||
|
||||
## Overflow
|
||||
|
||||
```html
|
||||
<div class="overflow-auto">Auto scroll</div>
|
||||
<div class="overflow-hidden">Hidden</div>
|
||||
<div class="overflow-scroll">Always scroll</div>
|
||||
<div class="overflow-x-auto">Horizontal scroll</div>
|
||||
<div class="overflow-y-hidden">No vertical scroll</div>
|
||||
```
|
||||
|
||||
## Opacity
|
||||
|
||||
```html
|
||||
<div class="opacity-0">0%</div>
|
||||
<div class="opacity-50">50%</div>
|
||||
<div class="opacity-75">75%</div>
|
||||
<div class="opacity-100">100%</div>
|
||||
```
|
||||
|
||||
## Cursor
|
||||
|
||||
```html
|
||||
<div class="cursor-pointer">Pointer</div>
|
||||
<div class="cursor-wait">Wait</div>
|
||||
<div class="cursor-not-allowed">Not allowed</div>
|
||||
<div class="cursor-default">Default</div>
|
||||
```
|
||||
|
||||
## User Select
|
||||
|
||||
```html
|
||||
<div class="select-none">No select</div>
|
||||
<div class="select-text">Text selectable</div>
|
||||
<div class="select-all">Select all</div>
|
||||
```
|
||||
Reference in New Issue
Block a user