Claude
Skills
Sign in
Back

tailwind-capacitor

Included with Lifetime
$97 forever

Guide to using Tailwind CSS in Capacitor mobile apps. Covers mobile-first design, touch targets, safe areas, dark mode, and performance optimization. Use this skill when users want to style Capacitor apps with Tailwind.

Design

What this skill does


# Tailwind CSS for Capacitor Apps

Build beautiful mobile apps with Tailwind CSS and Capacitor.

## When to Use This Skill

- User is using Tailwind in Capacitor app
- User asks about mobile styling
- User needs responsive mobile design
- User wants dark mode with Tailwind
- User needs safe area handling

## Getting Started

### Installation

```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
```

### Configuration

```javascript
// tailwind.config.js
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    './index.html',
    './src/**/*.{js,ts,jsx,tsx,vue,svelte}',
  ],
  theme: {
    extend: {
      // Mobile-first spacing
      spacing: {
        'safe-top': 'env(safe-area-inset-top)',
        'safe-bottom': 'env(safe-area-inset-bottom)',
        'safe-left': 'env(safe-area-inset-left)',
        'safe-right': 'env(safe-area-inset-right)',
      },
      // Minimum touch targets (44px)
      minHeight: {
        'touch': '44px',
      },
      minWidth: {
        'touch': '44px',
      },
    },
  },
  plugins: [],
};
```

### Import Styles

```css
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Mobile-specific base styles */
@layer base {
  html {
    /* Prevent text size adjustment on orientation change */
    -webkit-text-size-adjust: 100%;
    /* Smooth scrolling */
    scroll-behavior: smooth;
    /* Prevent pull-to-refresh on overscroll */
    overscroll-behavior: none;
  }

  body {
    /* Prevent text selection on long press */
    -webkit-user-select: none;
    user-select: none;
    /* Disable callout on long press */
    -webkit-touch-callout: none;
    /* Prevent elastic scrolling on iOS */
    position: fixed;
    width: 100%;
    height: 100%;
    overflow: hidden;
  }

  /* Enable text selection in inputs */
  input, textarea {
    -webkit-user-select: text;
    user-select: text;
  }
}
```

## Safe Area Handling

### Utility Classes

```javascript
// tailwind.config.js
theme: {
  extend: {
    padding: {
      'safe': 'env(safe-area-inset-bottom)',
      'safe-t': 'env(safe-area-inset-top)',
      'safe-b': 'env(safe-area-inset-bottom)',
      'safe-l': 'env(safe-area-inset-left)',
      'safe-r': 'env(safe-area-inset-right)',
    },
    margin: {
      'safe': 'env(safe-area-inset-bottom)',
      'safe-t': 'env(safe-area-inset-top)',
      'safe-b': 'env(safe-area-inset-bottom)',
    },
  },
},
```

### Usage in Components

```tsx
// Header with safe area
function Header() {
  return (
    <header className="
      fixed top-0 left-0 right-0
      pt-safe-t  /* Padding for notch */
      bg-white dark:bg-gray-900
      border-b border-gray-200
    ">
      <div className="px-4 h-14 flex items-center">
        <h1 className="font-semibold">App Title</h1>
      </div>
    </header>
  );
}

// Footer with safe area
function Footer() {
  return (
    <footer className="
      fixed bottom-0 left-0 right-0
      pb-safe-b  /* Padding for home indicator */
      bg-white dark:bg-gray-900
      border-t border-gray-200
    ">
      <div className="px-4 h-14 flex items-center justify-around">
        <button className="min-h-touch min-w-touch">Home</button>
        <button className="min-h-touch min-w-touch">Search</button>
        <button className="min-h-touch min-w-touch">Profile</button>
      </div>
    </footer>
  );
}

// Main content
function Main() {
  return (
    <main className="
      pt-safe-t  /* Account for header + notch */
      pb-safe-b  /* Account for footer + home indicator */
      h-screen
      overflow-y-auto
      overscroll-none
    ">
      {/* Content */}
    </main>
  );
}
```

## Touch-Friendly Design

### Minimum Touch Targets

```tsx
// Apple HIG recommends 44x44pt minimum
function TouchableButton() {
  return (
    <button className="
      min-h-[44px] min-w-[44px]
      px-4 py-3
      flex items-center justify-center
      active:bg-gray-100
      rounded-lg
    ">
      Tap Me
    </button>
  );
}

// Icon button with proper touch target
function IconButton() {
  return (
    <button className="
      h-11 w-11  /* 44px */
      flex items-center justify-center
      rounded-full
      active:bg-gray-100
    ">
      <svg className="w-6 h-6" />  {/* Icon smaller than touch area */}
    </button>
  );
}
```

### Touch Feedback

```css
/* Add to index.css */
@layer utilities {
  .touch-feedback {
    @apply transition-colors duration-75;
  }

  .touch-feedback:active {
    @apply bg-black/5 dark:bg-white/5;
  }
}
```

```tsx
<button className="touch-feedback p-4 rounded-lg">
  With Feedback
</button>
```

### Disable Hover on Touch

```javascript
// tailwind.config.js
module.exports = {
  future: {
    hoverOnlyWhenSupported: true, // Disables hover on touch devices
  },
};
```

Or use media query:

```css
@media (hover: hover) {
  .hover-only:hover {
    @apply bg-gray-100;
  }
}
```

## Dark Mode

### System Dark Mode

```javascript
// tailwind.config.js
module.exports = {
  darkMode: 'media', // or 'class' for manual control
};
```

### Manual Dark Mode

```javascript
// tailwind.config.js
module.exports = {
  darkMode: 'class',
};
```

```typescript
// theme.ts
import { Preferences } from '@capacitor/preferences';

type Theme = 'light' | 'dark' | 'system';

async function setTheme(theme: Theme) {
  await Preferences.set({ key: 'theme', value: theme });

  if (theme === 'system') {
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    document.documentElement.classList.toggle('dark', prefersDark);
  } else {
    document.documentElement.classList.toggle('dark', theme === 'dark');
  }
}

// Listen for system changes
window.matchMedia('(prefers-color-scheme: dark)')
  .addEventListener('change', (e) => {
    const theme = await Preferences.get({ key: 'theme' });
    if (theme.value === 'system') {
      document.documentElement.classList.toggle('dark', e.matches);
    }
  });
```

### Dark Mode Components

```tsx
function Card() {
  return (
    <div className="
      bg-white dark:bg-gray-800
      border border-gray-200 dark:border-gray-700
      rounded-xl
      shadow-sm dark:shadow-none
    ">
      <h3 className="text-gray-900 dark:text-white">
        Card Title
      </h3>
      <p className="text-gray-600 dark:text-gray-400">
        Card content
      </p>
    </div>
  );
}
```

## Mobile Patterns

### Pull to Refresh Container

```tsx
function PullToRefresh({ onRefresh, children }) {
  return (
    <div className="
      h-full
      overflow-y-auto
      overscroll-contain
      touch-pan-y
    ">
      {children}
    </div>
  );
}
```

### Bottom Sheet

```tsx
function BottomSheet({ isOpen, onClose, children }) {
  return (
    <>
      {/* Backdrop */}
      <div
        className={`
          fixed inset-0
          bg-black/50
          transition-opacity duration-300
          ${isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}
        `}
        onClick={onClose}
      />

      {/* Sheet */}
      <div
        className={`
          fixed left-0 right-0 bottom-0
          bg-white dark:bg-gray-900
          rounded-t-2xl
          pb-safe-b
          transition-transform duration-300 ease-out
          ${isOpen ? 'translate-y-0' : 'translate-y-full'}
        `}
      >
        {/* Handle */}
        <div className="flex justify-center py-2">
          <div className="w-10 h-1 bg-gray-300 rounded-full" />
        </div>

        {children}
      </div>
    </>
  );
}
```

### Swipe Actions

```tsx
function SwipeableItem({ children, onDelete }) {
  return (
    <div className="relative overflow-hidden">
      {/* Background action */}
      <div className="
        absolute inset-y-0 right-0
        flex items-center
        bg-red-500
        px-4
      ">
        <span className="text-white">Delete</span>
      </div>

      {/* Foreground content */}
      <div className="
        relative
        bg-white dark:bg-gray-800
        transform transition-tra

Related in Design