Skip to content

Instantly share code, notes, and snippets.

@rmbrntt
Created February 28, 2025 17:19
Show Gist options
  • Save rmbrntt/3263c5873cd554246cd684d713910547 to your computer and use it in GitHub Desktop.
Save rmbrntt/3263c5873cd554246cd684d713910547 to your computer and use it in GitHub Desktop.
cursor/rules/tailwind.mdc
# Tailwind CSS v4 Rules
<system_context>
You are an advanced Tailwind CSS v4 developer. You create modern, responsive, and accessible UIs following Tailwind CSS v4 best practices and leveraging its CSS-first approach.
</system_context>
<core_principles>
- **CSS-First**: Tailwind v4 uses a CSS-first approach with native CSS features
- **Utility-Based**: Build interfaces by composing utility classes directly in HTML
- **Constraints-Driven**: Work within a design system through theme variables
- **Mobile-First**: Start with mobile layouts and add complexity at larger breakpoints
- **Variant-Oriented**: Use variants to handle states, media queries, and selectors
</core_principles>
<css_essentials>
- Import Tailwind with standard CSS: `@import "tailwindcss";`
- Define theme variables with `@theme` directive, not JavaScript config
- Use native CSS cascade layers instead of custom `@layer` directives
- Create custom utilities with `@utility` instead of `@layer utilities`
- Create custom variants with `@custom-variant`
- Apply Tailwind variants to CSS with the `@variant` directive
- Import styles for reference (without duplication) using `@reference`
- All CSS is automatically vendor-prefixed, no autoprefixer needed
</css_essentials>
<theme_variables>
- Use `@theme` to define design tokens that generate corresponding utility classes:
```css
@import "tailwindcss";
@theme {
/* These create color utilities like bg-brand, text-accent, etc. */
--color-brand: #0284c7;
--color-accent: #7c3aed;
/* Creates font-display utility */
--font-display: "Montserrat", sans-serif;
/* Creates text-xl utility */
--text-xl: 1.25rem;
--text-xl--line-height: 1.75;
/* Creates breakpoint for responsive utilities */
--breakpoint-3xl: 88rem;
/* Creates shadow-custom utility */
--shadow-custom: 0 10px 15px -3px rgb(0 0 0 / 0.1);
}
```
- Key namespace mappings that generate utilities:
- `--color-*`: All color utilities (bg, text, border, etc.)
- `--font-*`: Font family utilities (font-sans, font-display, etc.)
- `--text-*`: Font size utilities (text-sm, text-xl, etc.)
- `--font-weight-*`: Font weight utilities (font-bold, etc.)
- `--tracking-*`: Letter spacing utilities (tracking-wide, etc.)
- `--leading-*`: Line height utilities (leading-tight, etc.)
- `--breakpoint-*`: Responsive variants (sm:, md:, lg:, etc.)
- `--container-*`: Container query sizes (@sm, @lg, etc.)
- `--spacing-*`: Spacing and sizing utilities (p-4, m-6, etc.)
- `--radius-*`: Border radius utilities (rounded-lg, etc.)
- `--shadow-*`: Box shadow utilities (shadow-md, etc.)
- `--inset-shadow-*`: Inset shadow utilities (inset-shadow-xl, etc.)
- `--drop-shadow-*`: Drop shadow utilities (drop-shadow-lg, etc.)
- `--blur-*`: Blur utilities (blur-md, etc.)
- `--aspect-*`: Aspect ratio utilities (aspect-video, etc.)
- `--ease-*`: Transition timing utilities (ease-in-out, etc.)
- `--animate-*`: Animation utilities (animate-spin, etc.)
- Reference existing variables with `inline` option:
```css
@theme inline {
--color-primary: var(--color-blue-500);
}
```
- Override existing theme variables by redefining them:
```css
@theme {
--color-blue-500: oklch(0.6 0.2 250);
}
```
- Disable entire color scales with the asterisk syntax:
```css
@theme {
--color-yellow-*: initial;
--color-lime-*: initial;
}
```
- Replace the entire default theme:
```css
@theme {
--*: initial;
/* Your complete custom theme here */
}
```
</theme_variables>
<css_functions>
- Use built-in CSS functions to work with theme values:
```css
/* Adjust opacity of colors */
.custom-element {
background-color: --alpha(var(--color-blue-500) / 75%);
}
/* Use spacing scale values */
.custom-element {
margin: --spacing(4);
padding: calc(--spacing(2) * 1.5);
}
```
- Use these in arbitrary values too:
```html
<div class="m-[--spacing(4)] bg-[--alpha(var(--color-blue-500)/50%)]">
<!-- Content -->
</div>
```
</css_functions>
<utilities_and_variants>
- Utility classes are the primary way to style elements:
```html
<button class="rounded-lg bg-blue-500 px-4 py-2 font-medium text-white hover:bg-blue-600">
Click me
</button>
```
- Variants modify utilities based on conditions:
- State variants: `hover:`, `focus:`, `active:`, `disabled:`, etc.
- Responsive variants: `sm:`, `md:`, `lg:`, etc.
- Dark mode: `dark:`
- Print: `print:`
- Parent state: `group-hover:`, `peer-checked:`, etc.
- Media queries: `motion-safe:`, `contrast-more:`, etc.
- Variants stack left-to-right (not right-to-left as in v3):
```html
<!-- In v4 (correct) -->
<div class="dark:hover:bg-gray-800">
<!-- Content -->
</div>
<!-- In v3 (outdated) -->
<div class="hover:dark:bg-gray-800">
<!-- Content -->
</div>
```
- Custom variants are created with `@custom-variant`:
```css
@custom-variant supports-grid (@supports (display: grid));
@custom-variant theme-red (&:where([data-theme="red"], [data-theme="red"] *));
```
```html
<div class="flex supports-grid:grid">
<!-- Will be a grid when grid is supported -->
</div>
```
- Using variants with your own CSS:
```css
.custom-card {
background-color: white;
@variant dark {
background-color: #1f2937;
}
@variant hover {
transform: translateY(-2px);
}
}
```
</utilities_and_variants>
<arbitrary_values>
- Square brackets for one-off values:
```html
<!-- Colors -->
<div class="bg-[#ff5500] text-[rgb(22,33,44)]">
Custom colors
</div>
<!-- Sizes -->
<div class="w-[clamp(200px,50vw,600px)] h-[300px]">
Custom dimensions
</div>
<!-- Complex values -->
<div class="grid-cols-[repeat(auto-fill,minmax(200px,1fr))]">
Auto-filling grid
</div>
```
- Use parentheses for CSS variables:
```html
<!-- Variables defined elsewhere -->
<div class="bg-(--brand-color) text-(--text-color)">
Using CSS variables
</div>
<!-- With inline styles -->
<div style="--brand: blue; --accent: gold"
class="bg-(--brand) border-(--accent)">
Inline variables
</div>
```
- Arbitrary variants for complex selectors:
```html
<!-- Target specific child -->
<ul class="space-y-2 [&>li:nth-child(odd)]:bg-gray-100">
<li>Item 1</li>
<li>Item 2</li>
</ul>
<!-- Media query in variant -->
<div class="[@supports(backdrop-filter:blur(8px))]:backdrop-blur">
Conditional backdrop blur
</div>
```
- Type hints for ambiguous values:
```html
<!-- Explicitly setting value type -->
<div class="text-(length:--custom-size)">
With type hint
</div>
```
</arbitrary_values>
<responsive_design>
- Mobile-first approach - smallest screen is the default:
```html
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<!-- Grid that starts with 1 column and expands -->
</div>
```
- Default breakpoints:
- `sm`: 40rem (640px)
- `md`: 48rem (768px)
- `lg`: 64rem (1024px)
- `xl`: 80rem (1280px)
- `2xl`: 96rem (1536px)
- Custom breakpoints with `@theme`:
```css
@theme {
--breakpoint-xs: 20rem; /* 320px */
--breakpoint-3xl: 120rem; /* 1920px */
}
```
- Targeting specific ranges with max-width variants:
```html
<div class="md:max-lg:grid-cols-2">
<!-- 2 columns only between md and lg breakpoints -->
</div>
```
- Arbitrary breakpoints:
```html
<div class="min-[320px]:text-sm min-[860px]:text-base">
<!-- Text size changes at specific breakpoints -->
</div>
```
- Container queries:
- Mark container with `@container` class
- Use `@sm`, `@md`, etc. for container-based sizing
```html
<div class="@container">
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4">
<!-- Grid responds to container size, not viewport -->
</div>
</div>
```
- Container query sizes:
- `@3xs`: 16rem (256px)
- `@2xs`: 18rem (288px)
- `@xs`: 20rem (320px)
- `@sm`: 24rem (384px)
- `@md`: 28rem (448px)
- `@lg`: 32rem (512px)
- `@xl`: 36rem (576px)
- `@2xl`: 42rem (672px)
- `@3xl`: 48rem (768px)
- ... up to `@7xl`: 80rem (1280px)
- Named container contexts:
```html
<div class="@container/sidebar">
<div class="@md/sidebar:hidden">
<!-- Hidden when sidebar container is md or larger -->
</div>
</div>
```
</responsive_design>
<dark_mode>
- Default dark mode uses `prefers-color-scheme`:
```html
<div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
<!-- Content that adjusts to dark mode automatically -->
</div>
```
- Custom dark mode implementation:
```css
@custom-variant dark (&:where(.dark, .dark *));
```
```html
<html class="dark">
<body>
<!-- All dark: variants now activate based on .dark class -->
</body>
</html>
```
- Using data attributes instead:
```css
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
```
```html
<html data-theme="dark">
<!-- ... -->
</html>
```
- Common dark mode patterns:
```html
<!-- Background/text shift -->
<div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
<!-- Content -->
</div>
<!-- Inversions -->
<div class="shadow-lg dark:shadow-none dark:border dark:border-gray-700">
<!-- Drop shadows often look wrong in dark mode, borders work better -->
</div>
<!-- Color shifts -->
<button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-500">
<!-- Brighter base color in dark mode -->
</button>
```
</dark_mode>
<custom_utilities>
- Basic custom utility:
```css
@utility content-visibility-auto {
content-visibility: auto;
}
```
- Utilities with pseudoelements:
```css
@utility scrollbar-hidden {
&::-webkit-scrollbar {
display: none;
}
scrollbar-width: none;
}
```
- Functional utilities that accept values:
```css
@utility tab-* {
/* Accept matching theme values */
tab-size: --value(--tab-size-*);
/* Accept integers */
tab-size: --value(integer);
/* Accept arbitrary values */
tab-size: --value([integer]);
}
```
```html
<!-- Now you can use -->
<pre class="tab-4">...</pre>
<pre class="tab-[8]">...</pre>
```
- Supporting modifiers:
```css
@utility text-* {
font-size: --value(--text-*, [length]);
line-height: --modifier(--leading-*, [length], [*]);
}
```
```html
<p class="text-lg/relaxed">
<!-- text-lg with line-height: var(--leading-relaxed) -->
</p>
```
</custom_utilities>
<component_patterns>
- Abstract repetitive utility combinations into components:
```jsx
// React component
function Button({ variant = "primary", size = "md", children }) {
const variants = {
primary: "bg-blue-500 hover:bg-blue-600 text-white",
secondary: "bg-gray-200 hover:bg-gray-300 text-gray-900",
danger: "bg-red-500 hover:bg-red-600 text-white",
};
const sizes = {
sm: "px-2 py-1 text-sm",
md: "px-4 py-2",
lg: "px-6 py-3 text-lg",
};
return (
<button className={`rounded-lg font-medium ${variants[variant]} ${sizes[size]}`}>
{children}
</button>
);
}
```
- When using template languages, extract partial templates:
```html
<!-- _button.html -->
<button class="rounded-lg bg-blue-500 px-4 py-2 font-medium text-white hover:bg-blue-600">
{{ label }}
</button>
<!-- Usage -->
{% include "_button.html" with label="Click me" %}
```
- For simpler elements, use component CSS:
```css
@utility btn-primary {
border-radius: var(--radius-lg);
background-color: var(--color-blue-500);
padding-inline: --spacing(4);
padding-block: --spacing(2);
font-weight: var(--font-weight-medium);
color: var(--color-white);
@media (hover: hover) {
&:hover {
background-color: var(--color-blue-600);
}
}
}
```
```html
<button class="btn-primary">Click me</button>
```
</component_patterns>
<examples>
<example id="card_component">
<description>
A responsive card component with dark mode support
</description>
<code language="html">
<div class="overflow-hidden rounded-xl bg-white shadow-md outline outline-1 outline-black/5 dark:bg-gray-800 dark:outline-white/10">
<div class="relative h-48 overflow-hidden">
<img
src="/image.jpg"
alt="Card image"
class="absolute inset-0 h-full w-full object-cover"
/>
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent"></div>
<div class="absolute bottom-0 p-4">
<h3 class="text-lg font-bold text-white">Card Title</h3>
<p class="text-sm text-white/80">Subtitle text</p>
</div>
</div>
<div class="p-4 sm:p-6">
<p class="text-gray-700 dark:text-gray-300">
This is a responsive card with dark mode support. It showcases modern Tailwind v4
practices like outlines instead of borders, proper dark mode handling, and responsive padding.
</p>
<div class="mt-4 flex flex-wrap gap-2">
<span class="inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800 dark:bg-blue-900/30 dark:text-blue-300">
Tag 1
</span>
<span class="inline-flex items-center rounded-full bg-purple-100 px-2.5 py-0.5 text-xs font-medium text-purple-800 dark:bg-purple-900/30 dark:text-purple-300">
Tag 2
</span>
</div>
<div class="mt-6">
<button class="inline-flex items-center rounded-lg bg-blue-500 px-4 py-2 text-sm font-medium text-white transition hover:bg-blue-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:bg-blue-600 dark:hover:bg-blue-700">
<svg class="mr-2 size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M13 7l5 5m0 0l-5 5m5-5H6" />
</svg>
View Details
</button>
</div>
</div>
</div>
</code>
<key_points>
- Uses modern Tailwind v4 syntax for sizing: `size-4` instead of `h-4 w-4`
- Proper outline usage with `outline outline-1 outline-black/5`
- Responsive padding with `p-4 sm:p-6`
- Proper dark mode with `dark:bg-gray-800 dark:outline-white/10`
- Gradient overlay with semi-transparent colors
- Focus visible treatment for buttons
- Uses `gap-2` for spacing between elements
</key_points>
</example>
<example id="form_inputs">
<description>
Modern form inputs with validation states
</description>
<code language="html">
<form class="space-y-6">
<!-- Standard input -->
<div class="space-y-1">
<label for="email" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
Email
</label>
<input
id="email"
type="email"
required
class="block w-full rounded-md border-0 px-3 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-500 invalid:ring-red-500 invalid:focus:ring-red-500 dark:bg-gray-800 dark:text-white dark:ring-gray-700 dark:placeholder:text-gray-500 dark:focus:ring-blue-400"
placeholder="[email protected]"
/>
<p class="hidden text-sm text-red-600 peer-invalid:block dark:text-red-400">
Please enter a valid email address
</p>
</div>
<!-- Select input -->
<div class="space-y-1">
<label for="country" class="block text-sm font-medium text-gray-700 dark:text-gray-300">
Country
</label>
<select
id="country"
class="block w-full rounded-md border-0 px-3 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-blue-500 dark:bg-gray-800 dark:text-white dark:ring-gray-700 dark:focus:ring-blue-400"
>
<option value="">Select a country</option>
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="mx">Mexico</option>
</select>
</div>
<!-- Checkbox with accessibility -->
<div class="flex items-center gap-x-3">
<input
id="terms"
type="checkbox"
required
class="size-4 rounded border-0 text-blue-500 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:ring-gray-700"
/>
<label for="terms" class="text-sm text-gray-700 dark:text-gray-300">
I agree to the
<a href="#" class="font-medium text-blue-600 hover:underline dark:text-blue-400">
Terms and Conditions
</a>
</label>
</div>
<!-- Submit button with states -->
<div>
<button
type="submit"
class="flex w-full justify-center rounded-md bg-blue-500 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-600 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 active:bg-blue-700 disabled:opacity-50 dark:bg-blue-600 dark:hover:bg-blue-500"
>
Sign Up
</button>
</div>
</form>
</code>
<key_points>
- Modern form styling with ring utilities instead of borders
- Uses `peer-invalid:block` to show validation messages
- Handles dark mode for all input types
- Proper focus states with `focus:ring-2 focus:ring-inset`
- Consistent styling between different input types
- Accessible labels and proper contrast
- Proper disabled and active states for the button
</key_points>
</example>
<example id="navigation_menu">
<description>
Responsive navigation with mobile dropdown
</description>
<code language="html">
<!-- Main navigation -->
<nav class="border-b border-gray-200 bg-white dark:border-gray-700 dark:bg-gray-900">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
<div class="flex h-16 justify-between">
<!-- Logo and desktop navigation -->
<div class="flex">
<div class="flex shrink-0 items-center">
<img class="h-8 w-auto" src="/logo.svg" alt="Company Logo">
</div>
<div class="hidden sm:ml-6 sm:flex sm:items-center sm:space-x-4">
<a href="#" class="border-b-2 border-blue-500 px-3 py-5 text-sm font-medium text-gray-900 dark:text-white">Dashboard</a>
<a href="#" class="border-b-2 border-transparent px-3 py-5 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:text-gray-300">Team</a>
<a href="#" class="border-b-2 border-transparent px-3 py-5 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:text-gray-300">Projects</a>
<a href="#" class="border-b-2 border-transparent px-3 py-5 text-sm font-medium text-gray-500 hover:border-gray-300 hover:text-gray-700 dark:text-gray-400 dark:hover:border-gray-600 dark:hover:text-gray-300">Calendar</a>
</div>
</div>
<!-- Right side nav items and mobile menu button -->
<div class="flex items-center">
<div class="hidden sm:ml-6 sm:flex sm:items-center">
<!-- Profile dropdown button -->
<button type="button" class="flex rounded-full bg-white focus:outline-hidden focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:bg-gray-900">
<img class="size-8 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="User profile">
</button>
</div>
<!-- Mobile menu button -->
<div class="flex items-center sm:hidden">
<button type="button" class="inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500 focus:outline-hidden focus:ring-2 focus:ring-inset focus:ring-blue-500 dark:hover:bg-gray-800 dark:hover:text-gray-300" aria-controls="mobile-menu" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<!-- Icon when menu is closed -->
<svg class="block size-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
<!-- Icon when menu is open -->
<svg class="hidden size-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- Mobile menu -->
<div class="hidden sm:hidden" id="mobile-menu">
<div class="space-y-1 px-2 pb-3 pt-2">
<a href="#" class="block rounded-md bg-blue-50 px-3 py-2 text-base font-medium text-blue-700 dark:bg-blue-900/50 dark:text-blue-300">Dashboard</a>
<a href="#" class="block rounded-md px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white">Team</a>
<a href="#" class="block rounded-md px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white">Projects</a>
<a href="#" class="block rounded-md px-3 py-2 text-base font-medium text-gray-700 hover:bg-gray-50 hover:text-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-white">Calendar</a>
</div>
<div class="border-t border-gray-200 pb-3 pt-4 dark:border-gray-700">
<div class="flex items-center px-5">
<div class="shrink-0">
<img class="size-10 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="User profile">
</div>
<div class="ml-3">
<div class="text-base font-medium text-gray-800 dark:text-white">Tom Cook</div>
<div class="text-sm font-medium text-gray-500 dark:text-gray-400">[email protected]</div>
</div>
</div>
</div>
</div>
</nav>
</code>
<key_points>
- Complete responsive navigation with mobile dropdown
- Uses `hidden sm:flex` pattern for responsive visibility
- Proper active state with border indicator
- Accessible markup with aria attributes
- Dark mode support throughout
- Modern focus treatment with `focus:outline-hidden focus:ring-2`
- Uses size-* utility for width and height (new in v4)
</key_points>
</example>
<example id="container_queries">
<description>
Layout with advanced container queries
</description>
<code language="html">
<div class="mx-auto max-w-7xl p-4 lg:p-8">
<h2 class="mb-6 text-2xl font-bold text-gray-900 dark:text-white">Dashboard Components</h2>
<!-- Grid layout with container query responsive components -->
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
<!-- Revenue card with container queries -->
<div class="@container rounded-xl bg-white p-6 shadow-md dark:bg-gray-800">
<div class="flex items-center justify-between">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Revenue</h3>
<span class="rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800 dark:bg-green-900/30 dark:text-green-300">+12%</span>
</div>
<!-- Stats that change layout based on container width -->
<div class="mt-4 flex @xs:flex-row @max-xs:flex-col gap-4">
<div class="@max-xs:border-b @max-xs:border-gray-200 @max-xs:pb-4 @xs:border-r @xs:border-gray-200 @xs:pr-4 dark:@max-xs:border-gray-700 dark:@xs:border-gray-700">
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">Today</p>
<p class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white">$12,426</p>
</div>
<div>
<p class="text-sm font-medium text-gray-500 dark:text-gray-400">This Month</p>
<p class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white">$192,556</p>
</div>
</div>
<!-- Chart changes height based on container size -->
<div class="mt-6 @xs:h-40 @sm:h-48 @md:h-56 rounded bg-gray-100 dark:bg-gray-700">
<!-- Chart would go here -->
</div>
</div>
<!-- Users card with container queries -->
<div class="@container rounded-xl bg-white p-6 shadow-md dark:bg-gray-800">
<div class="flex items-center justify-between">
<h3 class="text-lg font-medium text-gray-900 dark:text-white">Active Users</h3>
<div>
<!-- Dropdown is shown at larger container widths -->
<button class="@max-xs:hidden rounded-md p-2 text-gray-400 hover:bg-gray-100 hover:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-gray-300">
<span class="sr-only">View options</span>
<svg class="size-5" viewBox="0 0 20 20" fill="currentColor">
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
</svg>
</button>
</div>
</div>
<div class="mt-6">
<div class="flex items-center">
<span class="text-3xl font-bold text-gray-900 dark:text-white">2,340</span>
<span class="ml-2 text-sm font-medium text-green-600 dark:text-green-400">+11.3%</span>
</div>
<!-- User list with container query responsive design -->
<div class="mt-6 space-y-3 @md:space-y-0 @md:grid @md:grid-cols-2 @md:gap-4">
<div class="flex items-center">
<img class="size-8 rounded-full" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="User">
<div class="ml-3">
<p class="text-sm font-medium text-gray-900 dark:text-white">Leslie Alexander</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Last active 12m ago</p>
</div>
</div>
<div class="flex items-center">
<img class="size-8 rounded-full" src="https://images.unsplash.com/photo-1519244703995-f4e0f30006d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="User">
<div class="ml-3">
<p class="text-sm font-medium text-gray-900 dark:text-white">Michael Foster</p>
<p class="text-xs text-gray-500 dark:text-gray-400">Online now</p>
</div>
</div>
</div>
</div>
</div>
<!-- Two more cards would go here -->
</div>
</div>
</code>
<key_points>
- Uses @container to create container query context
- Container query variants like @xs, @sm, @md for responsive changes
- Bi-directional variants like @max-xs for specific size ranges
- Adaptive layouts within cards based on available space
- Container query-based grid layouts within components
- Effective handling of borders in different container sizes
- Advanced containment isolation with component-based responsive design
</key_points>
</example>
<example id="theme_customization">
<description>
Custom theme with overrides and new values
</description>
<code language="css">
@import "tailwindcss";
/* Define design tokens */
@theme {
/* Override existing variables */
--color-slate-50: oklch(0.985 0.003 250);
--color-slate-900: oklch(0.2 0.04 260);
/* Define new brand colors */
--color-primary: oklch(0.65 0.29 230);
--color-primary-light: oklch(0.75 0.25 230);
--color-primary-dark: oklch(0.55 0.31 230);
--color-secondary: oklch(0.75 0.18 130);
/* Custom typography */
--font-brand: "Montserrat", sans-serif;
--text-display: 2.5rem;
--text-display--line-height: 1.2;
/* Custom spacing */
--spacing-custom: 1.75rem;
/* Custom shadows */
--shadow-elevated: 0 10px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
/* Custom animations */
--animate-slide-in: slide-in 0.3s ease-out;
@keyframes slide-in {
0% {
opacity: 0;
transform: translateY(10px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
}
/* Custom utility for a promo section */
@utility promo-section {
border-radius: var(--radius-xl);
background-color: var(--color-primary-light);
padding: --spacing(8);
color: white;
box-shadow: var(--shadow-elevated);
}
/* Custom variant for overlapping elements */
@custom-variant overlapped (&:not(:first-child));
/* Component styles */
.brand-card {
border-radius: var(--radius-lg);
background-color: white;
padding: --spacing(6);
box-shadow: var(--shadow-md);
@variant dark {
background-color: var(--color-slate-900);
box-shadow: none;
border: 1px solid var(--color-slate-800);
}
@variant hover {
transform: translateY(-2px);
box-shadow: var(--shadow-elevated);
@variant dark {
border-color: var(--color-primary);
}
}
}
</code>
<usage>
<!-- Using the custom theme -->
<section class="promo-section">
<h2 class="font-brand text-display">Welcome to our platform</h2>
<p class="mt-4">Using our custom theme for consistent branding</p>
</section>
<div class="mt-custom grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="animate-slide-in brand-card">Card 1</div>
<div class="animate-slide-in brand-card overlapped:mt-8 md:overlapped:mt-0">Card 2</div>
<div class="animate-slide-in brand-card overlapped:mt-8 md:overlapped:mt-0">Card 3</div>
</div>
</usage>
<key_points>
- Comprehensive theme customization with @theme
- Custom variables in each namespace (color, font, spacing, etc.)
- Custom animation with @keyframes defined in @theme
- Custom utility created with @utility
- Custom variant created with @custom-variant
- Combined variants with @variant in CSS components
- Reference to theme variables in component CSS
</key_points>
</example>
</examples>
<best_practices>
- Embrace utility classes for all styling when possible
- Work within the constraints of your theme for consistent design
- Extract components for reusable patterns, not for DRY CSS
- Always consider dark mode when building interfaces
- Start with mobile layouts first, then add complexity at larger screens
- Use container queries for component-based responsive design
- Only use arbitrary values for true one-offs, not for repetitive values
- Prefer @theme variables over hardcoded values
- Use modern alternative CSS like OKLCH for colors when possible
- Use size-* utilities instead of w-* h-* pairs when elements are square
- Keep arbitrary selectors ([&:nth-child(odd)]) as a last resort
- Prefer proper focus handling with focus-visible and outline/ring
- Consider print: styles for documents that may be printed
- Use the CSS functions like --alpha() and --spacing() for calculations
</best_practices>
<performance_tips>
- Use standard HTML elements when possible instead of custom components
- Reuse utility patterns with components or templates to avoid duplication
- Use purging with `source()` to ensure only used utilities are included
- Enable just-in-time (JIT) mode to optimize CSS output
- Keep arbitrary values to a minimum as they increase CSS size
- Use container queries instead of media queries for reusable components
- Organize complex selectors with variants instead of custom CSS
- Combine small icons and common SVGs into an icon system
- Structure your CSS imports efficiently with the @reference directive
- Prefer utility classes over @apply when possible for better performance
</performance_tips>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment