Skip to main content

Overview

Chapinismos uses Tailwind CSS v4 integrated via the Vite plugin. The configuration is minimal by design, leveraging Tailwind’s new @theme directive in CSS for customization.

Tailwind Setup

Integration

Tailwind v4 is integrated through Vite in astro.config.mjs:
astro.config.mjs
import { defineConfig } from "astro/config";
import tailwindcss from "@tailwindcss/vite";

export default defineConfig({
  vite: {
    plugins: [tailwindcss()],
  },
});

Theme Configuration

Instead of a traditional tailwind.config.js file, Tailwind v4 uses the @theme directive in CSS:
src/styles/global.css
@import "tailwindcss";

@theme {
  /* Custom theme configuration */
  --color-primary: #60a5fa;
  --color-primary-light: #5fa8dc;
  --color-primary-dark: #3885bd;
  
  --font-sans: "Baloo 2 Variable", sans-serif;
  --font-title: "Alice", "Baloo 2 Variable", sans-serif;
}

Custom Utility Classes

Chapinismos extends Tailwind with custom utilities defined in the @layer utilities block:

Color Utilities

src/styles/global.css
@layer utilities {
  /* Text colors */
  .text-primary-light {
    color: var(--primary-light);
  }

  .text-primary {
    color: var(--link-primary);
  }

  .text-muted {
    color: var(--muted);
  }

  .text-theme {
    color: var(--text);
  }

  .text-secondary {
    color: var(--text-secondary);
  }

  /* Background colors */
  .bg-card {
    background-color: var(--card);
  }

  .bg-card-hover {
    background-color: var(--card-hover);
  }

  .bg-accent {
    background-color: var(--bg-accent);
  }

  .bg-glow-primary {
    background: var(--glow-primary);
  }

  /* Border colors */
  .border-theme {
    border-color: var(--border);
  }
}

Shadow Utilities

src/styles/global.css
@layer utilities {
  .shadow-theme-sm {
    box-shadow: 0 1px 2px var(--shadow-sm);
  }

  .shadow-theme-md {
    box-shadow: 0 2px 8px var(--shadow-sm);
  }

  .shadow-theme-lg {
    box-shadow: 0 4px 12px var(--shadow-md);
  }
}

Component Utilities

Reusable component patterns as utility classes:
src/styles/global.css
@layer utilities {
  /* Base card */
  .card-base {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
  }

  /* Card with gradient */
  .card-with-gradient {
    background: linear-gradient(180deg, var(--card) 0%, var(--bg-accent) 100%);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
  }

  /* Navigation link */
  .nav-link {
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    transition: all 0.2s ease;
  }

  .nav-link:hover {
    background: var(--card-hover);
    border-color: var(--border);
  }

  /* Article card */
  .article-card {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    box-shadow: 0 2px 8px var(--shadow-md);
  }

  /* Accent box with border */
  .accent-box {
    background: var(--bg-accent);
    border-left: 3px solid var(--primary-light);
  }

  /* Example box */
  .example-box {
    color: var(--muted);
    background: var(--glow-primary);
    border-left: 2px solid var(--primary);
    border-radius: var(--radius-md);
  }
}

Special Effects

src/styles/global.css
@layer utilities {
  /* Gradient text */
  .gradient-text {
    background-image: linear-gradient(to right, var(--text), var(--primary-light));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }

  /* Primary gradient badge */
  .badge-primary-gradient {
    background: linear-gradient(135deg, var(--primary-light), var(--primary));
    box-shadow: 0 2px 8px var(--shadow-md);
  }

  /* GT badge (Guatemala flag colors) */
  .gt-badge {
    background: var(--glow-primary);
    border: 1px solid var(--primary);
    color: var(--primary);
    border-radius: var(--radius-full);
  }
}

Using Custom Utilities

In Astro Components

src/components/ExampleCard.astro
---
// Component logic
---

<div class="card-base p-6 shadow-theme-md hover:shadow-theme-lg transition-shadow">
  <h2 class="text-theme text-2xl font-semibold mb-3">
    Card Title
  </h2>
  <p class="text-secondary leading-relaxed">
    Card content with theme-aware colors.
  </p>
  <a href="#" class="text-primary hover:text-primary-light transition-colors">
    Learn more →
  </a>
</div>

Combining with Tailwind Utilities

<!-- Mix custom utilities with Tailwind -->
<div class="card-base p-8 max-w-2xl mx-auto space-y-4">
  <div class="bg-glow-primary rounded-lg p-4">
    <span class="text-primary font-semibold">Highlighted content</span>
  </div>
</div>

<!-- Navigation link example -->
<a href="/" class="nav-link px-4 py-2 inline-flex items-center gap-2">
  <span class="text-theme">Home</span>
</a>

Extending Tailwind

Add New Color Utilities

src/styles/global.css
@layer utilities {
  /* Add accent color utilities */
  .text-accent {
    color: var(--accent);
  }

  .bg-accent-light {
    background-color: var(--accent-light);
  }

  .border-accent {
    border-color: var(--accent);
  }
}
Then define the CSS variable:
src/styles/global.css
:root {
  --accent: #f59e0b;        /* Amber */
  --accent-light: #fbbf24;
}

Add New Component Patterns

src/styles/global.css
@layer utilities {
  /* Notification badge */
  .badge-notification {
    background: linear-gradient(135deg, #ef4444, #dc2626);
    color: white;
    border-radius: var(--radius-full);
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.25rem 0.5rem;
  }

  /* Info panel */
  .info-panel {
    background: var(--glow-primary);
    border: 1px solid var(--primary);
    border-radius: var(--radius-lg);
    padding: 1rem;
  }

  /* Code block container */
  .code-container {
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
  }
}
Usage:
<div class="info-panel">
  <p class="text-primary font-semibold">Did you know?</p>
  <p class="text-secondary">Chapinismos are unique to Guatemala!</p>
</div>

<span class="badge-notification">New</span>

Add Animation Utilities

src/styles/global.css
@layer utilities {
  .animate-fade-in {
    animation: fadeIn 0.3s ease-in;
  }

  .animate-slide-up {
    animation: slideUp 0.4s ease-out;
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes slideUp {
  from {
    transform: translateY(20px);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

Responsive Design

Tailwind’s responsive utilities work seamlessly with custom utilities:
<div class="card-base p-4 md:p-6 lg:p-8">
  <h2 class="text-xl md:text-2xl lg:text-3xl text-theme">
    Responsive Title
  </h2>
  <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
    <!-- Cards -->
  </div>
</div>

Mobile-First Approach

<!-- Stack on mobile, horizontal on desktop -->
<nav class="flex flex-col md:flex-row gap-2 md:gap-4">
  <a href="#" class="nav-link px-4 py-2">Link 1</a>
  <a href="#" class="nav-link px-4 py-2">Link 2</a>
</nav>

<!-- Hide on mobile, show on desktop -->
<div class="hidden md:block bg-card p-6">
  Desktop-only content
</div>

Dark Mode Support

All custom utilities automatically support dark/light mode through CSS variables:
<!-- Same code works in both themes -->
<div class="bg-card border-theme text-theme">
  This adapts to dark/light mode automatically
</div>
No need for Tailwind’s dark: prefix since CSS variables handle theme switching.

Performance Tips

Use Custom Utilities for Repeated Patterns

Before:
<!-- Repeated in many places -->
<div class="bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg">
  Content
</div>
After:
<!-- Single utility class -->
<div class="card-base">
  Content
</div>

Avoid Arbitrary Values When Possible

Before:
<div class="text-[#60a5fa] bg-[rgba(96,165,250,0.1)]">
After:
<div class="text-primary bg-glow-primary">

Migrating from Tailwind v3

If you’re familiar with Tailwind v3, here are the key differences:

Configuration

Tailwind v3:
tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        primary: '#60a5fa',
      },
    },
  },
}
Tailwind v4:
src/styles/global.css
@theme {
  --color-primary: #60a5fa;
}

Integration

Tailwind v3:
import tailwind from '@astrojs/tailwind';

export default defineConfig({
  integrations: [tailwind()],
});
Tailwind v4:
import tailwindcss from '@tailwindcss/vite';

export default defineConfig({
  vite: {
    plugins: [tailwindcss()],
  },
});

Next Steps

Styling Architecture

Learn about CSS variables and global styles

Design System

Explore the complete design token reference

Build docs developers (and LLMs) love