Lzh on GitHub

Tailwind Variants 允许您使用 extend 属性或返回的函数轻松组合组件。

使用 extend 属性

extend 属性允许您扩展组件,包括它的 variantsslotsdefaultVariantscompoundVariants。它会自动合并同名键的值并提供 TypeScript 自动完成。

基本示例

import { tv } from 'tailwind-variants';
 
const baseButton = tv({
  base: [
    'font-semibold',
    'dark:text-white',
    'py-1',
    'px-3',
    'rounded-full',
    'active:opacity-80',
    'bg-zinc-100',
    'hover:bg-zinc-200',
    'dark:bg-zinc-800',
    'dark:hover:bg-zinc-800'
  ]
});
 
const buyButton = tv({
  extend: baseButton,
  base: [
    'text-sm',
    'text-white',
    'rounded-lg',
    'shadow-lg',
    'uppercase',
    'tracking-wider',
    'bg-blue-500',
    'hover:bg-blue-600',
    'shadow-blue-500/50',
    'dark:bg-blue-500',
    'dark:hover:bg-blue-600'
  ]
});
 
return (
  <div className="flex gap-3">
    <button className={baseButton()}>Button</button>
    <button className={buyButton()}>Buy button</button>
  </div>
);
 
/**
 * buyButton();
 *
 * Result:
 * font-semibold dark:text-white py-1 px-3 active:opacity-80 text-sm text-white rounded-lg
 * shadow-lg shadow-blue-500/50 uppercase tracking-wider bg-blue-500 hover:bg-blue-600
 * dark:bg-blue-500 dark:hover:bg-blue-600
 */

扩展带有变体的组件

带有 variants 的组件在组合时会继承它们的变体。

import { tv } from 'tailwind-variants';
 
const baseButton = tv({
  base: 'font-semibold text-white rounded-full active:opacity-80',
  variants: {
    color: {
      primary: 'bg-blue-500 hover:bg-blue-700',
      secondary: 'bg-purple-500 hover:bg-purple-700',
      success: 'bg-green-500 hover:bg-green-700'
    },
    size: {
      small: 'py-0 px-2 text-xs',
      medium: 'py-1 px-3 text-sm',
      large: 'py-1.5 px-3 text-md'
    }
  }
});
 
const myButton = tv({
  extend: baseButton,
  variants: {
    isSquared: {
      true: 'rounded-sm'
    }
  }
  // custom button styles
});
 
myButton({ color: 'success', size: 'medium', isSquared: true });
 
/**
 * Result:
 * font-semibold text-white active:opacity-80 rounded-sm bg-purple-500 hover:bg-purple-700 py-1 px-3 text-sm
 */

您还可以扩展带有 defaultVariantscompoundVariants 的组件。

import { tv } from 'tailwind-variants';
 
const baseButton = tv({
  base: 'font-semibold text-white rounded-full active:opacity-80',
  variants: {
    color: {
      primary: 'bg-blue-500 hover:bg-blue-700',
      secondary: 'bg-purple-500 hover:bg-purple-700',
      success: 'bg-green-500 hover:bg-green-700'
    },
    size: {
      small: 'py-0 px-2 text-xs',
      medium: 'py-1 px-3 text-sm',
      large: 'py-1.5 px-3 text-md'
    }
  },
  defaultVariants: {
    color: 'primary',
    size: 'medium'
  },
  compoundVariants: [
    {
      color: 'primary',
      size: 'medium',
      className: 'rounded-sm'
    }
  ]
});
 
const myButton = tv({
  extend: baseButton
  // custom button styles
});
 
myButton();
 
/**
 * Result:
 * font-semibold text-white active:opacity-80 bg-blue-500 hover:bg-blue-700 py-1 px-3 text-sm rounded-sm
 */
您可以通过将任何继承的 variantsdefaultVariantscompoundVariants 传递给组件来覆盖它们。

扩展带有插槽的组件

带有 slots 的组件在组合时会继承它们的插槽。

import { tv } from 'tailwind-variants';
 
const cardBase = tv({
  slots: {
    base: 'md:flex bg-slate-100 rounded-xl p-8 md:p-0 dark:bg-gray-900',
    avatar:
      'w-24 h-24 md:w-48 md:h-auto md:rounded-none rounded-full mx-auto drop-shadow-lg',
    wrapper: 'flex-1 pt-6 md:p-8 text-center md:text-left space-y-4',
    description: 'text-md font-medium',
    infoWrapper: 'font-medium',
    name: 'text-sm text-sky-500 dark:text-sky-400',
    role: 'text-sm text-slate-700 dark:text-slate-500'
  }
});
 
const myCard = tv({
  extend: cardBase
  // custom card styles
});
 
const { base, avatar, wrapper, description, infoWrapper, name, role } =
  myCard();
 
return (
  <figure className={base()}>
    <img
      className={avatar()}
      src="/intro-avatar.png"
      alt=""
      width="384"
      height="512"
    />
    <div className={wrapper()}>
      <blockquote>
        <p className={description()}>
          “Tailwind variants allows you to reduce repeated code in your project
          and make it more readable. They fixed the headache of building a
          design system with TailwindCSS.”
        </p>
      </blockquote>
      <figcaption className={infoWrapper()}>
        <div className={name()}>Zoey Lang</div>
        <div className={role()}>Full-stack developer, HeroUI</div>
      </figcaption>
    </div>
  </figure>
);
您可以通过向插槽键传递新值来覆盖任何继承的插槽。

使用结果

您可以使用 tv() 函数的结果来组合您的组件。但是,这种方法不具备类型安全,并且您必须使用 class / className 属性将结果传递给新组件。

在使用结果字符串组合组件时,您可以使用 base 键、slotsvariants。您使用的键应采用字符串数组的形式。

import { tv } from 'tailwind-variants';
 
const baseButton = tv({
  base: 'font-medium text-sm px-3 py-1 bg-blue-500 text-white rounded-full active:opacity-80'
});
 
const actionButton = tv({
  base: [baseButton(), 'bg-red-500', 'rounded-xs']
});
 
actionButton();
 
/**
 * Result:
 * font-medium text-sm px-3 py-1 text-white active:opacity-80 bg-red-500 rounded-xs
 */
重要的是将 base 样式放在前面,这样它们就可以被其他样式覆盖。