This document outlines the steps to create Badge
component styled withTailwind CSS and using some npm dependency libraries.
Node.js
and npm
installed on your machine.Tailwind CSS
installed in your project.CVA(class-variance-authority)
is a utility for managing CSS class names based on various conditions.clsx
is a tiny utility for constructing className strings conditionally.1// badge.helpers.ts
2import { cva } from "class-variance-authority";
3
4export const badgeVariants = cva(
5 "absolute flex justify-center items-center border-white px-[3px]",
6 {
7 variants: {
8 shape: {
9 square: "rounded-sm",
10 circle: "rounded-full",
11 },
12 size: {
13 small: "min-w-3 h-3 data-[outline=true]:border text-[9px]",
14 medium: "min-w-4 h-4 data-[outline=true]:border text-xs",
15 large: "min-w-5 h-5 data-[outline=true]:border-2 text-sm",
16 },
17 position: {
18 topRight: "",
19 topLeft: "",
20 bottomRight: "",
21 bottomLeft: "",
22 },
23 color: {
24 primary: "bg-blue-500 text-white",
25 secondary: "bg-gray-500 text-white",
26 success: "bg-green-500 text-white",
27 danger: "bg-red-500 text-white",
28 warning: "bg-yellow-500 text-white",
29 info: "bg-cyan-500 text-white",
30 light: "bg-gray-200 text-black",
31 dark: "bg-gray-900 text-white",
32 },
33 },
34 compoundVariants: [
35 {
36 position: "topRight",
37 size: "small",
38 className: "-top-1 left-[calc(100%-7px)]",
39 },
40 {
41 position: "topRight",
42 size: "medium",
43 className: "-top-1.5 left-[calc(100%-10px)]",
44 },
45 {
46 position: "topRight",
47 size: "large",
48 className: "-top-2 left-[calc(100%-12px)]",
49 },
50 {
51 position: "bottomRight",
52 size: "small",
53 className: "-bottom-1 left-[calc(100%-7px)]",
54 },
55 {
56 position: "bottomRight",
57 size: "medium",
58 className: "-bottom-1.5 left-[calc(100%-10px)]",
59 },
60 {
61 position: "bottomRight",
62 size: "large",
63 className: "-bottom-2 left-[calc(100%-12px)]",
64 },
65 {
66 position: "topLeft",
67 size: "small",
68 className: "-top-1 right-[calc(100%-7px)]",
69 },
70 {
71 position: "topLeft",
72 size: "medium",
73 className: "-top-1.5 right-[calc(100%-10px)]",
74 },
75 {
76 position: "topLeft",
77 size: "large",
78 className: "-top-2 right-[calc(100%-12px)]",
79 },
80 {
81 position: "bottomLeft",
82 size: "small",
83 className: "-bottom-1 right-[calc(100%-7px)]",
84 },
85 {
86 position: "bottomLeft",
87 size: "medium",
88 className: "-bottom-1.5 right-[calc(100%-10px)]",
89 },
90 {
91 position: "bottomLeft",
92 size: "large",
93 className: "-bottom-2 right-[calc(100%-12px)]",
94 },
95 ],
96 defaultVariants: {
97 shape: "square",
98 size: "medium",
99 color: "primary",
100 position: "topRight",
101 },
102 },
103);
104
1// badge.component.tsx
2import { VariantProps } from "class-variance-authority";
3import { badgeVariants } from "./badge.helpers";
4
5interface BadgeProps extends VariantProps<typeof badgeVariants> {
6 title: string;
7 showOutline?: boolean;
8 hidden?: boolean;
9 className?: string;
10 labelClassName?: string;
11 children: React.ReactNode;
12}
13
14const Badge: React.FC<BadgeProps> = ({
15 title,
16 shape,
17 size,
18 color,
19 position,
20 showOutline,
21 hidden,
22 className,
23 labelClassName,
24 children,
25}) => {
26 return (
27 <div className={cn("relative w-fit", className)}>
28 {children}
29 {!hidden && (
30 <div
31 data-outline={Boolean(showOutline).toString()}
32 className={cn(
33 badgeVariants({ shape, size, position, color }),
34 labelClassName
35 )}
36 >
37 {title}
38 </div>
39 )}
40 </div>
41 );
42};
43
44export default Badge;
45