go to article list
Photo by David Pisnoy on Unsplash
TLDR; This is likely the optimal approach for creating variants in react using tailwind
// @/lib/cn.ts
import clsx from "clsx";
import { ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// @/components/Button/Button.variants.ts
import { cva } from 'class-variance-authority';
const buttonSizes = {
sm: "w-8 h-6",
md: "w-12 h-8"
lg: "w-16 h-12",
};
const buttonColors = {
primary: "bg-blue-400",
danger: "bg-red-400",
warning: "bg-orange-400",
}
export const buttonVariants = cva(
'button',
{
variants: {
size: buttonSizes,
color: buttonColors
},
defaultVariants: {
size: 'md',
color: 'primary',
}
}
)
// @/components/Button/Button.tsx
import cn from '@/lib/cn';
import { VariantProps } from 'class-variance-authority';
import { buttonVariants } from './Button.variants.ts'
interface Props extends VariantProps<typeof buttonVariants> {
children: React.ReactNode;
className?: string;
}
const Button: React.FC<Props> = ({ children, size, color, className }) ⇒ {
return <button className={cn(buttonVariants({ size, color, className })}>{children}</button>
}
<button className={`bg-${color}-400`}></button>
// This would not register since the tailwind only detects classes on runtime, so it would not include bg-{dynamic}-400
// App.tsx
<CustomButton className={’bg-red-400’}>Test</CustomButton>
// CustomButton.tsx
<button className={classNames(’bg-blue-400’, className}>{children}</button>
npm install clsx tailwind-merge class-authority-variance
cn
functiontailwind-merge
makes sure that there are no conflicting classnames.
// @/lib/cn.ts
import clsx from "clsx";
import { ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
Button.variants.ts
This is optional, but I prefer using a modular folder structure, and that's why I like to keep things separated
// @/components/Button/Button.variants.ts
import { cva } from 'class-variance-authority';
const buttonSizes = {
sm: "w-8 h-6",
md: "w-12 h-8"
lg: "w-16 h-12",
};
const buttonColors = {
primary: "bg-blue-400",
danger: "bg-red-400",
warning: "bg-orange-400",
}
export const buttonVariants = cva(
'button',
{
variants: {
size: buttonSizes,
color: buttonColors
},
defaultVariants: {
size: 'md',
color: 'primary',
}
}
)
Button.tsx
component// @/components/Button/Button.tsx
import { cn } from '@/app/_utils/tailwind-merge';
import { VariantProps } from 'class-variance-authority';
import { buttonVariants } from './Button.variants.ts'
interface Props extends VariantProps<typeof buttonVariants> {
children: React.ReactNode;
className?: string;
}
const Button: React.FC<Props> = ({ children, size, color, className }) ⇒ {
return <button className={cn(buttonVariants({ size, color, className })}>{children}</button>
}
// @/App.tsx
import Button from './components/Button'
export default App() {
return <Button size="sm" color="warning">Warning!</Button>;
}
I've tried my fair share of tricks in creating variants. But guess what? This one takes the cake — and I'm not saying it's better, I'm saying it's a game-changer. Seriously, it's like finding the perfect playlist for your day. So much simpler, so much better. Try it, you won't be disappointed! 🚀
TAGS:
#best-practice
#react
#component variance
#tailwind
go to article list
Having trouble updating branches that is dependent to one another? Enter git-branch-updater
KEEP IT SIMPLE STUPID! EP1 - Pomodoro
The Right Way to Make Component Variants using Tailwind
Essential Tools and Libraries for Daily Web Development Works
How to Send Emails in Next.js 13 Using the New App API Route
Mastering React Testing: A Comprehensive Checklist of What to Test
Mastering Commit Messages: Best Practices and Examples
How to Integrate Contentful to Next 13
Real-Life Applications of Design Patterns in Your Daily React Code