Tailwind Ecosystem Integration Guide
This guide documents the Tailwind CSS ecosystem libraries installed in the cloudalt-frontend and provides best practices for their usage across web applications.
Installed Libraries
Section titled “Installed Libraries”Tier 1: Essential Utilities (Installed)
Section titled “Tier 1: Essential Utilities (Installed)”1. @headlessui/react
Section titled “1. @headlessui/react”Version: Latest
Purpose: Unstyled, fully accessible UI components from Tailwind Labs
Use Cases:
- Dropdowns and menus
- Modals and dialogs
- Tabs and accordions
- Transitions and animations
- Form components (Select, Radio, Checkbox, etc.)
Example:
import { Menu } from '@headlessui/react';
export function Dropdown() { return ( <Menu> <Menu.Button className="px-4 py-2 bg-primary-500 text-white rounded-md"> Options </Menu.Button> <Menu.Items className="absolute mt-2 w-56 bg-white shadow-lg rounded-md"> <Menu.Item> {({ active }) => ( <a className={`${active ? 'bg-primary-50' : ''} block px-4 py-2`} href="/account" > Account </a> )} </Menu.Item> </Menu.Items> </Menu> );}2. tailwind-merge
Section titled “2. tailwind-merge”Version: Latest
Purpose: Intelligent Tailwind class merging to prevent conflicts
Use Cases:
- Component libraries where users can override styles
- Conditional styling with multiple class sources
- Merging base classes with variant classes
Example (Used in Hero Component):
import { twMerge } from 'tailwind-merge';
export const Hero: React.FC<HeroProps> = ({ className, darkMode }) => { const bgClass = darkMode ? 'bg-gray-900' : 'bg-white';
return ( <section className={twMerge('relative overflow-hidden', bgClass, className)}> {/* Component content */} </section> );};Why it matters:
Without tailwind-merge, conflicting classes like bg-white bg-gray-900 would both be applied, causing unpredictable results. twMerge intelligently resolves conflicts by keeping only the last value for each CSS property.
3. clsx
Section titled “3. clsx”Version: Latest
Purpose: Utility for conditionally constructing className strings
Use Cases:
- Conditional styling based on state
- Combining multiple class sources
- Cleaner conditional rendering
Example:
import clsx from 'clsx';
export function Alert({ type, className }) { return ( <div className={clsx( 'p-4 rounded-md', { 'bg-red-100 text-red-800': type === 'error', 'bg-green-100 text-green-800': type === 'success', 'bg-blue-100 text-blue-800': type === 'info', }, className )}> {/* Alert content */} </div> );}4. tailwind-variants
Section titled “4. tailwind-variants”Version: Latest
Purpose: Type-safe variant system for Tailwind components (CVA alternative)
Use Cases:
- Creating reusable components with multiple variants
- Type-safe styling with full TypeScript support
- Compound variants for complex styling logic
Example (Used in Button Component):
import { tv, type VariantProps } from 'tailwind-variants';
const button = tv({ base: 'inline-flex items-center justify-center font-medium transition-colors', variants: { color: { primary: 'bg-primary-500 text-white hover:bg-primary-600', secondary: 'bg-gray-500 text-white hover:bg-gray-600', outline: 'border-2 border-primary-500 text-primary-500', }, size: { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2 text-base', lg: 'px-6 py-3 text-lg', }, }, defaultVariants: { color: 'primary', size: 'md', },});
export type ButtonVariants = VariantProps<typeof button>;
export const Button = ({ color, size, children }) => { return ( <button className={button({ color, size })}> {children} </button> );};Component Implementation Examples
Section titled “Component Implementation Examples”Enhanced Hero Component
Section titled “Enhanced Hero Component”The Hero component now uses tailwind-merge for intelligent className merging:
Location: packages/ui-stay-match/src/components/Hero/Hero.tsx
Key Features:
- Users can pass custom
classNameprop to override or extend base styles - Conflicting classes are automatically resolved
- Dark mode classes merge cleanly with custom classes
Usage:
<Hero title="Welcome" description="Your description" ctaText="Get Started" onCtaPress={() => {}} className="my-custom-class bg-gradient-to-r from-purple-500"/>Button Component with Variants
Section titled “Button Component with Variants”The Button component demonstrates type-safe variants using tailwind-variants:
Location: packages/ui-stay-match/src/components/Button/Button.tsx
Key Features:
- Four color variants: primary, secondary, outline, ghost
- Three size variants: sm, md, lg
- Loading state with spinner
- Disabled state
- Full width option
- Full TypeScript support with autocomplete
Usage:
import { Button } from '@cloudalt-frontend/ui-stay-match';
// Basic usage<Button>Click Me</Button>
// With variants<Button color="secondary" size="lg">Large Secondary Button</Button>
// Loading state<Button isLoading>Loading...</Button>
// Full width<Button fullWidth>Full Width Button</Button>
// Custom classes (merged with clsx)<Button className="shadow-lg">Custom Styled Button</Button>Best Practices
Section titled “Best Practices”1. Component Design Pattern
Section titled “1. Component Design Pattern”When creating new components, follow this pattern:
import { tv } from 'tailwind-variants';import { twMerge } from 'tailwind-merge';import clsx from 'clsx';
// Define variantsconst componentVariants = tv({ base: 'base-classes', variants: { variant: { default: 'variant-classes', }, },});
// Componentexport const Component = ({ variant, className, ...props }) => { return ( <div className={twMerge( componentVariants({ variant }), clsx(className) )}> {/* Content */} </div> );};2. When to Use Each Library
Section titled “2. When to Use Each Library”| Library | Use When |
|---|---|
| @headlessui/react | Building complex interactive UI (dropdowns, modals, tabs) |
| tailwind-merge | Merging classes from multiple sources, especially in component libraries |
| clsx | Conditional styling based on state or props |
| tailwind-variants | Creating components with multiple style variants |
3. Combining Libraries
Section titled “3. Combining Libraries”These libraries work together seamlessly:
import { Menu } from '@headlessui/react';import { tv } from 'tailwind-variants';import { twMerge } from 'tailwind-merge';import clsx from 'clsx';
const menuItem = tv({ base: 'block px-4 py-2 text-sm', variants: { active: { true: 'bg-primary-50 text-primary-700', false: 'text-gray-700', }, },});
export function Dropdown() { return ( <Menu> <Menu.Button>Options</Menu.Button> <Menu.Items> <Menu.Item> {({ active }) => ( <a className={twMerge(menuItem({ active }))}> Account </a> )} </Menu.Item> </Menu.Items> </Menu> );}Tier 2: High Value (Recommended for Future)
Section titled “Tier 2: High Value (Recommended for Future)”@tailwindcss/forms
Section titled “@tailwindcss/forms”Purpose: Better form defaults and styling
When to install: When building forms-heavy features
@tailwindcss/typography
Section titled “@tailwindcss/typography”Purpose: Beautiful typographic defaults for content
When to install: When building blog/content features
Migration Path
Section titled “Migration Path”For existing components:
- Identify components with className conflicts → Add
tailwind-merge - Components with multiple visual variants → Refactor with
tailwind-variants - Complex conditional styling → Simplify with
clsx - Custom dropdowns/modals → Replace with
@headlessui/react
React Native Comparison
Section titled “React Native Comparison”| React Native | Web (Tailwind) | Purpose |
|---|---|---|
| react-native-paper | @headlessui/react + Tailwind | Component library |
| StyleSheet with conditionals | clsx | Conditional styling |
| Custom variant props | tailwind-variants | Type-safe variants |
| react-navigation | @headlessui/react (Menu/Dialog) | Navigation UI |
| react-native-vector-icons | Heroicons / Custom SVG | Icons |