Skip to content

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.

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>
);
}

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.

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>
);
}

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>
);
};

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 className prop 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"
/>

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>

When creating new components, follow this pattern:

import { tv } from 'tailwind-variants';
import { twMerge } from 'tailwind-merge';
import clsx from 'clsx';
// Define variants
const componentVariants = tv({
base: 'base-classes',
variants: {
variant: {
default: 'variant-classes',
},
},
});
// Component
export const Component = ({ variant, className, ...props }) => {
return (
<div className={twMerge(
componentVariants({ variant }),
clsx(className)
)}>
{/* Content */}
</div>
);
};
LibraryUse When
@headlessui/reactBuilding complex interactive UI (dropdowns, modals, tabs)
tailwind-mergeMerging classes from multiple sources, especially in component libraries
clsxConditional styling based on state or props
tailwind-variantsCreating components with multiple style variants

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>
);
}
Section titled “Tier 2: High Value (Recommended for Future)”

Purpose: Better form defaults and styling
When to install: When building forms-heavy features

Purpose: Beautiful typographic defaults for content
When to install: When building blog/content features

For existing components:

  1. Identify components with className conflicts → Add tailwind-merge
  2. Components with multiple visual variants → Refactor with tailwind-variants
  3. Complex conditional styling → Simplify with clsx
  4. Custom dropdowns/modals → Replace with @headlessui/react
React NativeWeb (Tailwind)Purpose
react-native-paper@headlessui/react + TailwindComponent library
StyleSheet with conditionalsclsxConditional styling
Custom variant propstailwind-variantsType-safe variants
react-navigation@headlessui/react (Menu/Dialog)Navigation UI
react-native-vector-iconsHeroicons / Custom SVGIcons