npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

tw-combine

v1.0.0

Published

A utility function that combines clsx and tailwind-merge for optimal Tailwind CSS class merging

Downloads

19

Readme

tw-combine

npm version License: MIT TypeScript

Uma utility function que combina clsx e tailwind-merge para uma mesclagem otimizada de classes Tailwind CSS.

🚀 Características

  • Combina clsx e tailwind-merge - Melhor dos dois mundos
  • Resolve conflitos automaticamente - Remove classes conflitantes do Tailwind
  • Suporte completo ao TypeScript - Tipagem forte e IntelliSense
  • Bundle pequeno - Apenas ~2KB gzipped
  • Zero dependências - Apenas clsx e tailwind-merge como peer dependencies
  • Compatível com todos os frameworks - React, Vue, Svelte, etc.

📦 Instalação

npm install tw-combine clsx tailwind-merge
yarn add tw-combine clsx tailwind-merge
pnpm add tw-combine clsx tailwind-merge

🎯 Uso Básico

import { twCombine } from 'tw-combine';

// Combinação simples
twCombine('px-4 py-2', 'bg-blue-500', 'text-white');
// Resultado: 'px-4 py-2 bg-blue-500 text-white'

// Classes condicionais
const isActive = true;
twCombine('px-4', { 'bg-blue-500': isActive }, { 'bg-gray-500': !isActive });
// Resultado: 'px-4 bg-blue-500'

// Resolução de conflitos
twCombine('px-4 px-6', 'py-2 py-4');
// Resultado: 'px-6 py-4' (conflitos resolvidos automaticamente)

🔧 Exemplos Avançados

Componente React

import { twCombine } from 'tw-combine';

interface ButtonProps {
  variant?: 'primary' | 'secondary';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  className?: string;
}

const Button: React.FC<ButtonProps> = ({
  variant = 'primary',
  size = 'md',
  disabled = false,
  className,
  children
}) => {
  return (
    <button
      className={twCombine(
        // Classes base
        'px-4 py-2 rounded font-medium transition-colors',

        // Variantes
        {
          'bg-blue-500 text-white hover:bg-blue-600': variant === 'primary',
          'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary',
        },

        // Tamanhos
        {
          'px-2 py-1 text-sm': size === 'sm',
          'px-4 py-2 text-base': size === 'md',
          'px-6 py-3 text-lg': size === 'lg',
        },

        // Estados
        {
          'opacity-50 cursor-not-allowed': disabled,
          'cursor-pointer': !disabled,
        },

        // Classes customizadas
        className
      )}
      disabled={disabled}
    >
      {children}
    </button>
  );
};

Componente Vue

<template>
  <button :class="buttonClasses">
    <slot />
  </button>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { twCombine } from 'tw-combine';

interface Props {
  variant?: 'primary' | 'secondary';
  size?: 'sm' | 'md' | 'lg';
  disabled?: boolean;
  className?: string;
}

const props = withDefaults(defineProps<Props>(), {
  variant: 'primary',
  size: 'md',
  disabled: false,
});

const buttonClasses = computed(() =>
  twCombine(
    'px-4 py-2 rounded font-medium transition-colors',
    {
      'bg-blue-500 text-white hover:bg-blue-600': props.variant === 'primary',
      'bg-gray-200 text-gray-900 hover:bg-gray-300': props.variant === 'secondary',
    },
    {
      'px-2 py-1 text-sm': props.size === 'sm',
      'px-4 py-2 text-base': props.size === 'md',
      'px-6 py-3 text-lg': props.size === 'lg',
    },
    {
      'opacity-50 cursor-not-allowed': props.disabled,
      'cursor-pointer': !props.disabled,
    },
    props.className
  )
);
</script>

Componente Svelte

<script lang="ts">
  import { twCombine } from 'tw-combine';

  export let variant: 'primary' | 'secondary' = 'primary';
  export let size: 'sm' | 'md' | 'lg' = 'md';
  export let disabled: boolean = false;
  export let className: string = '';

  $: buttonClasses = twCombine(
    'px-4 py-2 rounded font-medium transition-colors',
    {
      'bg-blue-500 text-white hover:bg-blue-600': variant === 'primary',
      'bg-gray-200 text-gray-900 hover:bg-gray-300': variant === 'secondary',
    },
    {
      'px-2 py-1 text-sm': size === 'sm',
      'px-4 py-2 text-base': size === 'md',
      'px-6 py-3 text-lg': size === 'lg',
    },
    {
      'opacity-50 cursor-not-allowed': disabled,
      'cursor-pointer': !disabled,
    },
    className
  );
</script>

<button class={buttonClasses} {disabled}>
  <slot />
</button>

🎨 Casos de Uso Comuns

Cards Responsivos

const cardClasses = twCombine(
  'bg-white rounded-lg shadow-md p-6',
  'hover:shadow-lg transition-shadow',
  {
    'border-l-4 border-blue-500': isHighlighted,
    'border-l-4 border-gray-300': !isHighlighted,
  },
  {
    'p-4': size === 'sm',
    'p-6': size === 'md',
    'p-8': size === 'lg',
  }
);

Navegação com Estados Ativos

const navItemClasses = (isActive: boolean) => twCombine(
  'px-4 py-2 rounded-md transition-colors',
  {
    'bg-blue-100 text-blue-700 font-semibold': isActive,
    'text-gray-600 hover:bg-gray-100 hover:text-gray-900': !isActive,
  }
);

Formulários com Validação

const inputClasses = (hasError: boolean, isDisabled: boolean) => twCombine(
  'w-full px-3 py-2 border rounded-md transition-colors',
  {
    'border-red-300 focus:border-red-500 focus:ring-red-500': hasError,
    'border-gray-300 focus:border-blue-500 focus:ring-blue-500': !hasError,
  },
  {
    'opacity-50 cursor-not-allowed': isDisabled,
    'cursor-text': !isDisabled,
  }
);

🔍 Como Funciona

O tw-combine funciona em duas etapas:

  1. clsx - Combina e filtra classes condicionais, removendo valores falsy
  2. tailwind-merge - Resolve conflitos entre classes do Tailwind CSS
// Exemplo do processo interno
const classes = ['px-4', 'px-6', { 'py-2': true }, { 'py-4': false }];

// 1. clsx processa as classes
const clsxResult = clsx(...classes); // 'px-4 px-6 py-2'

// 2. tailwind-merge resolve conflitos
const finalResult = twMerge(clsxResult); // 'px-6 py-2'

📚 API

twCombine(...classes)

Combina classes CSS usando clsx e resolve conflitos com tailwind-merge.

Parâmetros:

  • ...classes - Array de strings, objetos condicionais, ou valores undefined/null

Retorna:

  • string - String de classes combinadas e otimizadas

Tipos:

type ClassValue = string | boolean | undefined | null;
type ClassObject = Record<string, boolean | undefined | null>;

function twCombine(...classes: (ClassValue | ClassObject)[]): string;

🧪 Testes

npm test
npm run test:watch

🛠️ Desenvolvimento

# Instalar dependências
npm install

# Modo desenvolvimento
npm run dev

# Build
npm run build

# Lint
npm run lint

# Type check
npm run type-check

📄 Licença

MIT © adachidev

🤝 Contribuição

Contribuições são bem-vindas! Por favor, abra uma issue ou pull request.

🔗 Links Relacionados

  • clsx - Utility for constructing className strings
  • tailwind-merge - Merge Tailwind CSS classes without style conflicts
  • Tailwind CSS - A utility-first CSS framework