--- name: tailwind-capacitor description: 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. --- # 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 bun add -D tailwindcss postcss autoprefixer bunx 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 (

App Title

); } // Footer with safe area function Footer() { return ( ); } // Main content function Main() { return (
{/* Content */}
); } ``` ## Touch-Friendly Design ### Minimum Touch Targets ```tsx // Apple HIG recommends 44x44pt minimum function TouchableButton() { return ( ); } // Icon button with proper touch target function IconButton() { return ( ); } ``` ### 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 ``` ### 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 (

Card Title

Card content

); } ``` ## Mobile Patterns ### Pull to Refresh Container ```tsx function PullToRefresh({ onRefresh, children }) { return (
{children}
); } ``` ### Bottom Sheet ```tsx function BottomSheet({ isOpen, onClose, children }) { return ( <> {/* Backdrop */}
{/* Sheet */}
{/* Handle */}
{children}
); } ``` ### Swipe Actions ```tsx function SwipeableItem({ children, onDelete }) { return (
{/* Background action */}
Delete
{/* Foreground content */}
{children}
); } ``` ### Fixed Header with Blur ```tsx function BlurHeader() { return (

Title

); } ``` ## Performance Optimization ### Reduce Bundle Size ```javascript // tailwind.config.js module.exports = { content: [/* ... */], // Only include used utilities safelist: [], // Add dynamic classes here if needed }; ``` ### GPU Acceleration ```tsx // Use transform for animations (GPU accelerated)
Animated Element
``` ### Avoid Layout Thrashing ```tsx // BAD: Causes reflow
// GOOD: Fixed dimensions
``` ## Component Examples ### Mobile List Item ```tsx function ListItem({ title, subtitle, image, onClick }) { return ( ); } ``` ### Mobile Button ```tsx function MobileButton({ children, variant = 'primary', ...props }) { const variants = { primary: 'bg-blue-500 text-white active:bg-blue-600', secondary: 'bg-gray-100 text-gray-900 active:bg-gray-200', danger: 'bg-red-500 text-white active:bg-red-600', }; return ( ); } ``` ### Mobile Input ```tsx function MobileInput({ label, error, ...props }) { return ( ); } ``` ## Resources - Tailwind CSS Documentation: https://tailwindcss.com/docs - Tailwind Mobile Patterns: https://tailwindui.com/ - CSS Safe Area Guide: https://webkit.org/blog/7929/designing-websites-for-iphone-x/