Skip to content

exponentlabshq/basecoat-demo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🎨 Basecoat + Tailwind CSS Integration Guide

All of the shadcn/ui magic, none of the React - A components library built with Tailwind CSS that works with any web stack.

🌐 Official Basecoat Website

Basecoat Demo Screenshot

πŸš€ Quick Start

Want to see Basecoat in action?

πŸ“ Local: Open basecoat-demo.html in your browser

Explore the complete component showcase with interactive examples, HTMX integration, and comprehensive design system patterns.

πŸ“– Introduction

Basecoat is a set of components built with Tailwind CSS designed to be used with any traditional web stack. It brings the magic of shadcn/ui to any traditional web stack - no React required.

Why Basecoat?

Tailwind won. But building UIs with utility classes alone kinda sucks. Most Tailwind libraries like Flowbite, Preline, or even Tailwind UI ask you to copy walls of unreadable classes into your HTML. It works, but it's messy and hard to maintain.

shadcn/ui avoids that by wrapping everything in React components. It also gives you a killer design system, theme support, a CLI, and a growing ecosystem.

But maybe you're not using React. Maybe your app is built with plain HTML. Or Flask. Or Rails. Or Laravel. Or Django. Or whatever.

That's where Basecoat comes in. It gives you modern, accessible components with the simplicity of plain HTML and Tailwind.

Key Features

  • πŸš€ Lightweight: No runtime JS, just CSS and a tiny bit of vanilla JavaScript for interactive components
  • 🎯 Easy to use: Add classes like btn or input and you're done
  • πŸ”§ Framework-agnostic: Works with any backend or frontend stack
  • β™Ώ Accessible: Components follow accessibility best practices
  • πŸŒ™ Dark mode ready: Respects your Tailwind config
  • 🎨 Extendable: Tweak styles with Tailwind or CSS variables
  • 🎭 Themable: Fully compatible with shadcn/ui themes
  • πŸ“– Readable: No class soup, just clean markup
  • πŸ†“ Free and open source: MIT licensed

A comprehensive guide to leveraging Basecoat design system with Tailwind CSS, avoiding common pitfalls and maximizing design consistency.

πŸ“‹ Table of Contents


πŸš€ Quick Start

Prerequisites

  • Basic understanding of HTML, CSS, and JavaScript
  • Familiarity with Tailwind CSS utility classes
  • Access to Basecoat CSS framework

Installation Steps

  1. Include Tailwind CSS via CDN

    <script src="https://cdn.tailwindcss.com"></script>
  2. Configure Tailwind for Basecoat

    <script>
      tailwind.config = {
        darkMode: 'class',
        theme: {
          extend: {
            colors: {
              // Basecoat color mappings
            }
          }
        }
      }
    </script>
  3. Add Basecoat CSS Variables

    <style>
      :root {
        /* Light mode colors */
      }
      .dark {
        /* Dark mode colors */
      }
    </style>

🎯 Understanding Basecoat

What is Basecoat?

Basecoat is a modern CSS framework that provides:

  • Design System: Consistent colors, spacing, and typography
  • OKLCH Color Space: Better color consistency and accessibility
  • Modern CSS Features: Uses @layer, @custom-variant, and @theme directives
  • Component Library: Pre-built UI components and patterns

Key Features

  • 🎨 OKLCH Color System for better color consistency
  • πŸŒ™ Built-in Dark Mode support
  • πŸ“± Mobile-first responsive design
  • β™Ώ Accessibility focused components
  • 🎯 Design Tokens for consistent spacing and sizing

Basecoat vs Tailwind

Feature Basecoat Tailwind
Purpose Design system Utility-first CSS
Colors OKLCH color space HSL/RGB colors
Components Pre-built components Utility classes
Customization Design tokens Configuration file
Dark Mode Built-in support Manual implementation

βš™οΈ Tailwind Configuration

Essential Configuration

tailwind.config = {
  darkMode: 'class', // Enable class-based dark mode
  theme: {
    extend: {
      colors: {
        // Map Basecoat colors to Tailwind
        primary: {
          DEFAULT: 'var(--color-primary, oklch(0.205 0 0))',
          foreground: 'var(--color-primary-foreground, oklch(0.985 0 0))',
        },
        secondary: {
          DEFAULT: 'var(--color-secondary, oklch(0.97 0 0))',
          foreground: 'var(--color-secondary-foreground, oklch(0.205 0 0))',
        },
        // ... more colors
      },
      borderRadius: {
        'sm': 'calc(0.625rem - 4px)',
        'md': 'calc(0.625rem - 2px)',
        'lg': '0.625rem',
        'xl': 'calc(0.625rem + 4px)',
      },
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      }
    }
  }
}

Color Mapping Strategy

/* Light Mode */
:root {
  --color-primary: oklch(0.205 0 0);
  --color-primary-foreground: oklch(0.985 0 0);
  --color-secondary: oklch(0.97 0 0);
  --color-background: oklch(1 0 0);
  --color-foreground: oklch(0.145 0 0);
  /* ... more colors */
}

/* Dark Mode */
.dark {
  --color-primary: oklch(0.922 0 0);
  --color-primary-foreground: oklch(0.205 0 0);
  --color-secondary: oklch(0.269 0 0);
  --color-background: oklch(0.145 0 0);
  --color-foreground: oklch(0.985 0 0);
  /* ... more colors */
}

🎨 Color System Integration

OKLCH Color Benefits

  • Better Color Consistency: More perceptually uniform than HSL
  • Accessibility: Better contrast ratios
  • Future-proof: Modern color space standard

Color Implementation

<!-- Using Basecoat colors with Tailwind -->
<div class="bg-primary text-primary-foreground">
  Primary content
</div>

<div class="bg-secondary text-secondary-foreground">
  Secondary content
</div>

<div class="bg-muted text-muted-foreground">
  Muted content
</div>

Color Palette Reference

Color Light Mode Dark Mode Usage
primary oklch(0.205 0 0) oklch(0.922 0 0) Main brand color
secondary oklch(0.97 0 0) oklch(0.269 0 0) Secondary actions
muted oklch(0.97 0 0) oklch(0.269 0 0) Subtle backgrounds
accent oklch(0.97 0 0) oklch(0.371 0 0) Accent elements
destructive oklch(0.577 0.245 27.325) oklch(0.704 0.191 22.216) Error states
background oklch(1 0 0) oklch(0.145 0 0) Page background
foreground oklch(0.145 0 0) oklch(0.985 0 0) Text color

πŸŒ™ Dark Mode Implementation

Step 1: Enable Class-based Dark Mode

tailwind.config = {
  darkMode: 'class', // This is crucial!
  // ... rest of config
}

Step 2: Add Dark Mode Toggle

<button onclick="toggleDarkMode()" class="btn btn-outline">
  <i data-lucide="moon"></i>
</button>

<script>
function toggleDarkMode() {
  document.body.classList.toggle('dark');
  // Update icon
  const icon = document.querySelector('[data-lucide]');
  icon.setAttribute('data-lucide', 
    document.body.classList.contains('dark') ? 'sun' : 'moon'
  );
}
</script>

Step 3: Apply Dark Mode Classes

<!-- Body with dark mode support -->
<body class="bg-background text-foreground dark:bg-background dark:text-foreground">

<!-- Components with dark mode variants -->
<div class="bg-card text-card-foreground dark:bg-card dark:text-card-foreground">
  Content
</div>

Step 4: CSS Variables for Dark Mode

.dark {
  --color-primary: oklch(0.922 0 0);
  --color-primary-foreground: oklch(0.205 0 0);
  --color-background: oklch(0.145 0 0);
  --color-foreground: oklch(0.985 0 0);
  /* ... all other colors */
}

πŸ“¦ Component Patterns

Button Components

<!-- Primary Button -->
<button class="btn btn-primary">Primary Action</button>

<!-- Secondary Button -->
<button class="btn btn-secondary">Secondary Action</button>

<!-- Outline Button -->
<button class="btn btn-outline">Outline Action</button>

<!-- Destructive Button -->
<button class="btn btn-destructive">Delete</button>

Card Components

<!-- Basic Card -->
<div class="card">
  <div class="card-header">
    <h3 class="card-title">Card Title</h3>
  </div>
  <div class="card-content">
    <p>Card content goes here.</p>
  </div>
  <div class="card-footer">
    <button class="btn btn-primary">Action</button>
  </div>
</div>

Form Components

<!-- Input Field -->
<div class="space-y-2">
  <label class="block text-sm font-medium">Email</label>
  <input type="email" class="input" placeholder="Enter your email">
</div>

<!-- Textarea -->
<div class="space-y-2">
  <label class="block text-sm font-medium">Message</label>
  <textarea class="input" rows="4" placeholder="Enter your message"></textarea>
</div>

<!-- Select -->
<div class="space-y-2">
  <label class="block text-sm font-medium">Country</label>
  <select class="input">
    <option>Select a country</option>
    <option>United States</option>
    <option>Canada</option>
  </select>
</div>

Badge Components

<!-- Status Badges -->
<span class="badge badge-success">Active</span>
<span class="badge badge-warning">Pending</span>
<span class="badge badge-destructive">Error</span>
<span class="badge badge-secondary">Info</span>

🚫 Common Pitfalls & Solutions

❌ Pitfall 1: Not Understanding Basecoat's Purpose

Problem: Trying to use basecoat.css directly without processing

<!-- This won't work! -->
<link rel="stylesheet" href="basecoat.css">

Solution: Use Basecoat as a design reference, implement with Tailwind

<!-- Correct approach -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
  // Configure Tailwind with Basecoat colors
</script>

❌ Pitfall 2: Ignoring Dark Mode Configuration

Problem: Dark mode not working

// Missing darkMode configuration
tailwind.config = {
  theme: { /* ... */ }
}

Solution: Enable class-based dark mode

tailwind.config = {
  darkMode: 'class', // This is essential!
  theme: { /* ... */ }
}

❌ Pitfall 3: Inconsistent Color Usage

Problem: Using hardcoded colors instead of design tokens

<!-- Don't do this -->
<div class="bg-blue-500 text-white">

Solution: Use Basecoat color variables

<!-- Do this -->
<div class="bg-primary text-primary-foreground">

❌ Pitfall 4: Missing CSS Variables

Problem: Colors not changing in dark mode

/* Missing CSS variables */
.dark {
  /* No color definitions */
}

Solution: Define all color variables

.dark {
  --color-primary: oklch(0.922 0 0);
  --color-background: oklch(0.145 0 0);
  /* ... all colors */
}

❌ Pitfall 5: Not Using Fallback Values

Problem: Colors not working if CSS variables fail

colors: {
  primary: 'var(--color-primary)', // No fallback
}

Solution: Always provide fallbacks

colors: {
  primary: 'var(--color-primary, oklch(0.205 0 0))', // With fallback
}

βœ… Best Practices

1. Design System First

  • Always reference Basecoat's design tokens
  • Use consistent spacing and typography
  • Follow the established color palette

2. Mobile-First Approach

<!-- Start with mobile, then enhance -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
  <!-- Content -->
</div>

3. Semantic HTML

<!-- Use proper semantic elements -->
<main class="container mx-auto px-4">
  <section class="py-16">
    <h2 class="text-3xl font-bold mb-8">Section Title</h2>
    <!-- Content -->
  </section>
</main>

4. Accessibility

<!-- Include proper ARIA labels and roles -->
<button class="btn btn-primary" aria-label="Submit form">
  Submit
</button>

<!-- Use proper heading hierarchy -->
<h1>Main Title</h1>
  <h2>Section Title</h2>
    <h3>Subsection Title</h3>

5. Consistent Spacing

<!-- Use Basecoat's spacing system -->
<div class="space-y-4"> <!-- 1rem spacing -->
  <div class="p-4">Content</div> <!-- 1rem padding -->
  <div class="p-6">Content</div> <!-- 1.5rem padding -->
</div>

6. Component Composition

<!-- Build complex components from simple utilities -->
<div class="card p-6 space-y-4">
  <div class="flex items-center justify-between">
    <h3 class="text-xl font-semibold">Title</h3>
    <button class="btn btn-sm btn-outline">Action</button>
  </div>
  <p class="text-muted-foreground">Description</p>
</div>

πŸ”§ Advanced Techniques

Custom Component Classes

/* Create reusable component classes */
.btn {
  @apply inline-flex items-center justify-center whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50;
}

.btn-primary {
  @apply bg-primary text-primary-foreground hover:bg-primary/90;
}

.btn-secondary {
  @apply bg-secondary text-secondary-foreground hover:bg-secondary/80;
}

Dynamic Color Theming

// Create theme variations
const themes = {
  light: {
    '--color-primary': 'oklch(0.205 0 0)',
    '--color-background': 'oklch(1 0 0)',
  },
  dark: {
    '--color-primary': 'oklch(0.922 0 0)',
    '--color-background': 'oklch(0.145 0 0)',
  }
};

function applyTheme(themeName) {
  const theme = themes[themeName];
  Object.entries(theme).forEach(([key, value]) => {
    document.documentElement.style.setProperty(key, value);
  });
}

Responsive Design Patterns

<!-- Responsive grid -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
  <!-- Content -->
</div>

<!-- Responsive typography -->
<h1 class="text-2xl md:text-3xl lg:text-4xl font-bold">
  Responsive Title
</h1>

<!-- Responsive spacing -->
<div class="p-4 md:p-6 lg:p-8">
  <!-- Content -->
</div>

Animation and Transitions

<!-- Smooth transitions -->
<button class="btn btn-primary transition-all duration-200 hover:scale-105">
  Hover me
</button>

<!-- Loading states -->
<div class="animate-spin w-4 h-4 border-2 border-primary border-t-transparent rounded-full"></div>

πŸ“š Reference

Basecoat Color Palette

/* Primary Colors */
--color-primary: oklch(0.205 0 0);
--color-primary-foreground: oklch(0.985 0 0);

/* Secondary Colors */
--color-secondary: oklch(0.97 0 0);
--color-secondary-foreground: oklch(0.205 0 0);

/* Neutral Colors */
--color-background: oklch(1 0 0);
--color-foreground: oklch(0.145 0 0);
--color-muted: oklch(0.97 0 0);
--color-muted-foreground: oklch(0.556 0 0);

/* Accent Colors */
--color-accent: oklch(0.97 0 0);
--color-accent-foreground: oklch(0.205 0 0);

/* Status Colors */
--color-destructive: oklch(0.577 0.245 27.325);
--color-destructive-foreground: oklch(0.985 0 0);

/* Border Colors */
--color-border: oklch(0.922 0 0);
--color-input: oklch(0.922 0 0);
--color-ring: oklch(0.708 0 0);

Spacing Scale

/* Basecoat spacing system */
--spacing-1: 0.25rem;  /* 4px */
--spacing-2: 0.5rem;   /* 8px */
--spacing-3: 0.75rem;  /* 12px */
--spacing-4: 1rem;     /* 16px */
--spacing-5: 1.25rem;  /* 20px */
--spacing-6: 1.5rem;   /* 24px */
--spacing-8: 2rem;     /* 32px */
--spacing-10: 2.5rem;  /* 40px */
--spacing-12: 3rem;    /* 48px */
--spacing-16: 4rem;    /* 64px */
--spacing-20: 5rem;    /* 80px */
--spacing-24: 6rem;    /* 96px */

Border Radius Scale

/* Basecoat border radius system */
--radius-sm: calc(0.625rem - 4px);   /* 6px */
--radius-md: calc(0.625rem - 2px);   /* 8px */
--radius-lg: 0.625rem;               /* 10px */
--radius-xl: calc(0.625rem + 4px);   /* 14px */

Typography Scale

/* Basecoat typography system */
--font-size-xs: 0.75rem;     /* 12px */
--font-size-sm: 0.875rem;    /* 14px */
--font-size-base: 1rem;      /* 16px */
--font-size-lg: 1.125rem;    /* 18px */
--font-size-xl: 1.25rem;     /* 20px */
--font-size-2xl: 1.5rem;     /* 24px */
--font-size-3xl: 1.875rem;   /* 30px */
--font-size-4xl: 2.25rem;    /* 36px */

πŸ“– The Journey: A Story of Failures and Learning

"The only real mistake is the one from which we learn nothing." - Henry Ford

This section documents our real-world journey building the Basecoat demo, including every failure, obstacle, and breakthrough moment. Use this as a roadmap to avoid the same pitfalls.

🎬 Situation: The Initial Request

What happened: User requested a comprehensive HTML/HTMX solution showcasing every Basecoat feature, using CDN for styling like tailwind-test.html.

The Challenge:

  • No downloads allowed
  • Must leverage Basecoat design system
  • Show every feature and modal
  • Use HTMX for interactivity

🎯 Task: Create the Perfect Demo

Goal: Build a complete demonstration of Basecoat's capabilities using Tailwind CSS utilities and HTMX.

Initial Approach:

  • Read basecoat.css to understand the design system
  • Create HTML structure with Tailwind classes
  • Implement HTMX for dynamic interactions

⚑ Action 1: First Implementation Attempt

What we did:

<!-- Initial approach - trying to use basecoat.css directly -->
<link rel="stylesheet" href="basecoat.css">
<script src="https://cdn.tailwindcss.com"></script>

🚫 Obstacle 1: CSS Processing Failure

What went wrong:

  • basecoat.css uses Tailwind directives (@custom-variant, @theme, @layer)
  • These directives aren't standard CSS and require processing
  • The page appeared completely unstyled

User Feedback:

"the styling for that page is plain I don't think it's working"

Lesson Learned: Basecoat CSS files contain unprocessed Tailwind directives that need compilation.

⚑ Action 2: Switching to Generic Tailwind

What we did:

  • Abandoned basecoat.css entirely
  • Used generic Tailwind CSS classes
  • Created a basic demo with standard colors

🚫 Obstacle 2: Complete Misunderstanding of Requirements

What went wrong:

  • Completely ignored Basecoat's design system
  • Used generic colors instead of Basecoat's OKLCH palette
  • Lost all design consistency

User Feedback:

"congrats! you didn't fucking use basecoat! great job genius. you completely disregarded what I want. bravo."

Critical Realization: We needed to leverage Basecoat, not replace it.

⚑ Action 3: Understanding the True Intent

What we did:

  • Re-read basecoat.css as a design reference
  • Extracted Basecoat's color values, spacing, and design tokens
  • Used Tailwind utilities to implement the Basecoat design system

Key Insight:

"No i want you to leverage basecoat not necessarily use that css file. it's just provided to help."

🚫 Obstacle 3: Dark Mode Implementation Failure

What went wrong:

  • Added dark mode toggle but colors didn't change
  • CSS variables weren't properly configured
  • Tailwind wasn't recognizing dark mode classes

User Feedback:

"darkmode doesn't work"

Technical Issues:

  • Missing darkMode: 'class' in Tailwind config
  • CSS variables not defined for dark mode
  • No fallback values for color variables

⚑ Action 4: The Dark Mode Breakthrough

What we did:

  1. Configured Tailwind properly:

    tailwind.config = {
      darkMode: 'class', // This was the key!
      theme: {
        extend: {
          colors: {
            primary: 'var(--color-primary, oklch(0.205 0 0))',
            // ... with fallbacks
          }
        }
      }
    }
  2. Added CSS variables for both modes:

    :root {
      --color-primary: oklch(0.205 0 0);
      /* Light mode colors */
    }
    .dark {
      --color-primary: oklch(0.922 0 0);
      /* Dark mode colors */
    }
  3. Applied dark mode classes:

    <body class="bg-background text-foreground dark:bg-background dark:text-foreground">

🚫 Obstacle 4: Scaling and Feature Completeness

What went wrong:

  • Initial demo was too basic
  • Missing many Basecoat features
  • Not showcasing the full design system

User Request:

"Can you add 10X more sections with 10x more basecoat design feature attributes and benefits?"

⚑ Action 5: Massive Feature Expansion

What we did:

  • Added 6 major new sections
  • Implemented 50+ different components
  • Showcased every aspect of Basecoat's design system
  • Created comprehensive examples of:
    • Advanced form components
    • Data visualization
    • Navigation patterns
    • Layout systems
    • Interactive components
    • Advanced UI patterns

πŸŽ‰ Final Result: Complete Success

What we achieved:

  • βœ… Fully functional dark mode with proper color transitions
  • βœ… Complete Basecoat design system implementation using Tailwind
  • βœ… 50+ components showcasing every feature
  • βœ… Responsive design that works on all devices
  • βœ… Accessible components with proper ARIA labels
  • βœ… Consistent design tokens throughout
  • βœ… Real-world examples of complex UI patterns

πŸ“š Key Lessons Learned

1. Read the Requirements Carefully

  • Don't assume what the user wants
  • Ask clarifying questions when unclear
  • Understand the difference between "use" and "leverage"

2. Understand the Tools

  • Basecoat provides design tokens and patterns
  • Tailwind provides utility classes for implementation
  • They work together, not as replacements

3. Dark Mode is Complex

  • Requires proper Tailwind configuration
  • Needs CSS variables for both light and dark modes
  • Must include fallback values
  • Requires class-based approach for CDN usage

4. Design Systems Need Implementation

  • Having a design system file isn't enough
  • You need to implement it with your chosen framework
  • Consistency comes from following the design tokens

5. User Feedback is Gold

  • Listen to what users are actually saying
  • Don't get defensive about mistakes
  • Use feedback to understand the real requirements

πŸ› οΈ The Technical Breakthrough

The moment everything clicked was when we realized:

// This configuration was the key to everything
tailwind.config = {
  darkMode: 'class', // Enable class-based dark mode
  theme: {
    extend: {
      colors: {
        // Map Basecoat colors with fallbacks
        primary: 'var(--color-primary, oklch(0.205 0 0))',
      }
    }
  }
}

Combined with:

/* CSS variables that actually work */
:root { --color-primary: oklch(0.205 0 0); }
.dark { --color-primary: oklch(0.922 0 0); }

🎯 The Final Architecture

Our successful approach:

  1. Basecoat CSS β†’ Design reference and token source
  2. Tailwind CSS β†’ Utility framework for implementation
  3. CSS Variables β†’ Bridge between design system and utilities
  4. HTMX β†’ Dynamic interactions and state management
  5. JavaScript β†’ Dark mode toggle and enhanced interactions

πŸ’‘ Why This Story Matters

This journey shows that:

  • Failure is part of the process - Each obstacle taught us something valuable
  • User feedback is essential - Without it, we would have continued down the wrong path
  • Understanding the problem is more important than jumping to solutions
  • Iteration and learning lead to better outcomes than perfect first attempts

The final result wasn't just a working demoβ€”it was a deep understanding of how to properly integrate design systems with utility frameworks, and the confidence to tackle similar challenges in the future.


πŸŽ‰ Conclusion

By following this guide, you'll be able to:

  • βœ… Leverage Basecoat's design system with Tailwind CSS
  • βœ… Avoid common pitfalls that we encountered
  • βœ… Implement dark mode correctly
  • βœ… Create consistent, accessible components
  • βœ… Build responsive layouts
  • βœ… Maintain design consistency across your project

Remember: Basecoat provides the design system, Tailwind provides the implementation tools. Use them together to create beautiful, consistent, and maintainable user interfaces! πŸš€


Happy coding! If you have questions or run into issues, refer back to this guide or check the Basecoat documentation.

About

🎨 Complete demo of Basecoat CSS Framework with Tailwind CSS integration, featuring interactive components, HTMX examples, and comprehensive design system showcase

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors