组合样式
Tailwind Variants 允许您使用 extend 属性或返回的函数轻松组合组件。
使用 extend 属性
extend 属性允许您扩展组件,包括它的 variants、slots、defaultVariants 和 compoundVariants。它会自动合并同名键的值并提供 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
*/
您还可以扩展带有 defaultVariants 和 compoundVariants 的组件。
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
*/
您可以通过将任何继承的
variants、defaultVariants 和 compoundVariants 传递给组件来覆盖它们。扩展带有插槽的组件
带有 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 键、slots 或 variants。您使用的键应采用字符串数组的形式。
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 样式放在前面,这样它们就可以被其他样式覆盖。