Badge
Displays a badge or a component that looks like a badge.
Installation
Install the component Badge in your project using the CLI.
Badge.tsx
pnpm dlx behsseui@latest add BadgeInstall the component manually.
Create a ui folder at the root of the project, then a component folder inside it, and finally a Badge.tsx file in that folder.
Copy and paste the following code into your project.
ui/components/Badge.tsx
1import type { HTMLAttributes, ReactNode } from "react";2import { Slot, type AsChildProps } from "./internals/Slot";3import { cva, type VariantProps } from "class-variance-authority"4import { cn } from "@/lib/utils";56const badgeVariants = cva(7 "inline-flex items-center justify-center gap-1.5 rounded-full text-xs font-medium transition-colors whitespace-nowrap shrink-0 [&>svg]:pointer-events-none [&>svg]:shrink-0 [&>svg]:size-3 [&>svg]:mt-px",8 {9 variants: {10 variant: {11 default: "bg-primary text-primary-foreground",12 secondary: "bg-secondary text-secondary-foreground",13 destructive: "bg-destructive text-destructive-foreground",14 outline: "border border-border bg-background text-foreground",15 ghost: "hover:bg-accent hover:text-accent-foreground",16 },17 size: {18 default: "h-6 px-2.5 py-0.5",19 sm: "h-5 px-2 py-0.5 text-[10px]",20 lg: "h-7 px-3 py-1",21 },22 },23 defaultVariants: {24 variant: "default",25 size: "default",26 },27 }28);2930type Props = AsChildProps<31 {32 children: ReactNode;33 className?: string;34 } & VariantProps<typeof badgeVariants>,35 HTMLAttributes<HTMLSpanElement>36>;3738export function Badge({39 variant = "default",40 size = "default",41 children,42 className,43 asChild,44 ...props45}: Props) {46 const Component = asChild ? Slot : "span";47 return (48 <Component className={cn(badgeVariants({ variant, size, className }))} {...props}>49 {children}50 </Component>51 );52}53For Badge.tsx to work, create an internals folder inside ui/component, then create a Slot.tsx file in it with the following code.
ui/components/internals/Slot.tsx
1import {2 Children,3 cloneElement,4 isValidElement,5 type HTMLAttributes,6 type PropsWithChildren,7 type ReactElement,8 type ReactNode,9} from "react";10import { twMerge } from "tailwind-merge";1112// Type utilitaire pour simplifier le typage des composant supportant asChild13export type AsChildProps<BaseProps, SecondaryProps = {}> =14 | ({ asChild: true; children: ReactNode } & BaseProps)15 | ({ asChild?: false; children?: ReactNode } & BaseProps & SecondaryProps);1617export function Slot(props: PropsWithChildren<HTMLAttributes<HTMLElement>>) {18 const children = Children.toArray(props.children).filter((c) =>19 isValidElement(c)20 );2122 if (children.length !== 1) {23 throw new Error("Slot must have exactly one child element");24 }2526 const child = children[0] as ReactElement<HTMLAttributes<HTMLElement>>;2728 return cloneElement(child, {29 ...props,30 ...child.props,31 style:32 props.style || child.props.style33 ? {34 ...props.style,35 ...child.props.style,36 }37 : undefined,38 className:39 props.className || child.props.className40 ? twMerge(props.className, child.props.className)41 : undefined,42 });43}Usages
Different variants and use cases for the Badge component.
Variants
Different badge variants for various contexts.
Variants.tsx
<div className="flex items-center gap-2">
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="ghost">Ghost</Badge>
</div>With Icons
Badges can include icons at the start or end.
With Icons.tsx
import Check from "@/ui/icons/Check"
import AlertCircle from "@/ui/icons/AlertCircle"
<div className="flex items-center gap-2">
<Badge>
<Check className="h-3 w-3" />
Success
</Badge>
<Badge variant="destructive">
Error
<AlertCircle className="h-3 w-3" />
</Badge>
</div>AsChild
Use the asChild prop to render the badge as a link or other element.
AsChild.tsx
import ArrowUpRight from "@/ui/icons/ArrowUpRight"
<Badge asChild>
<a href="https://ui.behsse.com">
Link Badge
<ArrowUpRight className="h-3 w-3" />
</a>
</Badge>