shadimage
asanshay
componentbadgesource: ok · hit

Badge

A clean set of badge components with an edible look.

npx shadcn add "https://ds.asanshay.com/r/badge.json"
free

Visual style

minimal

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
ui-primitives@radix-ui/react-slot

Files1 · source cached 10/9/2026, 8:06:09 AM

registry/new-york/blocks/badge/badge.tsx
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils";

type Color = "emerald" | "red" | "amber" | "sky" | "indigo" | "orange" | "primary";

const colorVariantsFancy = {
  primary:
    "border-primary/10 from-primary/10 to-primary/50 hover:bg-primary/10 text-primary/80  dark:from-primary/30 dark:hover:bg-primary/10",
  emerald:
    "border-emerald-300 from-emerald-200/20 to-emerald-300  hover:bg-emerald-100 text-emerald-600  dark:hover:bg-emerald/10 dark:from-emerald-700/50 dark:text-emerald-400",
  red: "border-red-300 from-red-200/50 to-red-400/80 hover:bg-red-100 text-red-600 dark:hover:bg-red/30 dark:from-red-700/20 dark:to-transparent dark:text-red-400",
  amber:
    "border-amber-300 from-amber-200/20 to-amber-200 hover:bg-amber-100 text-amber-600 dark:hover:bg-amber/30 dark:from-amber-700/50 dark:text-amber-400",
  sky: "border-sky-300 from-sky-200/20 to-sky-300 hover:bg-sky-100 text-sky-600 dark:hover:bg-sky/30 dark:from-sky-700/50 dark:text-sky-400",
  indigo:
    "border-indigo-300 from-indigo-200/20 to-indigo-300 hover:bg-indigo-100 text-indigo-600 dark:hover:bg-indigo/30 dark:from-indigo-700/50 dark:text-indigo-400",
  orange:
    "border-orange-300 from-orange-200/20 to-orange-300 hover:bg-orange-100 text-orange-600 dark:hover:bg-orange/30 dark:from-orange-700/50 dark:text-orange-400",
};

const colorVariantsRegular = {
  primary:
    "bg-primary/10 hover:bg-primary/20 text-primary/80 dark:bg-primary/10 dark:hover:bg-primary/10",
  emerald:
    "bg-emerald-100 hover:bg-emerald-200 text-emerald-600 dark:bg-emerald-600/10 dark:hover:bg-emerald-600/30 dark:text-emerald-400",
  red: "bg-red-100 hover:bg-red-200 text-red-600 dark:bg-red-600/10 dark:hover:bg-red-600/30 dark:text-red-400",
  amber:
    "bg-amber-100 hover:bg-amber-200 text-amber-600 dark:bg-amber-500/10 dark:hover:bg-amber-600/30 dark:text-amber-400",
  sky: "bg-sky-100 hover:bg-sky-200 text-sky-600 dark:bg-sky-500/10 dark:hover:bg-sky-600/30 dark:text-sky-400",
  indigo:
    "bg-indigo-100 hover:bg-indigo-200 text-indigo-600 dark:bg-indigo-500/10 dark:hover:bg-indigo-600/30 dark:text-indigo-400",
  orange:
    "bg-orange-100 hover:bg-orange-200 text-orange-600 dark:bg-orange-500/10 dark:hover:bg-orange-600/30 dark:text-orange-400",
};

const colorVariantsOutline = {
  primary:
    "hover:bg-primary/10 hover:border-primary/80 [&>svg]:text-primary dark:hover:bg-primary/10 dark:hover:border-primary/80",
  emerald:
    "hover:bg-emerald-100 hover:border-emerald-300 [&>svg]:text-emerald-400 dark:hover:bg-emerald-600/10 dark:hover:border-emerald-300",
  red: "hover:bg-red-100 hover:border-red-300 [&>svg]:text-red-400 dark:hover:bg-red-600/10 dark:hover:border-red-300",
  amber:
    "hover:bg-amber-100 hover:border-amber-300 [&>svg]:text-amber-400 dark:hover:bg-amber-600/10 dark:hover:border-amber-300",
  sky: "hover:bg-sky-100 hover:border-sky-300 [&>svg]:text-sky-400 dark:hover:bg-sky-600/10 dark:hover:border-sky-300",
  indigo:
    "hover:bg-indigo-100 hover:border-indigo-300 [&>svg]:text-indigo-400 dark:hover:bg-indigo-600/10 dark:hover:border-indigo-300",
  orange:
    "hover:bg-orange-100 hover:border-orange-300 [&>svg]:text-orange-400 dark:hover:bg-orange-600/10 dark:hover:border-orange-300",
};

const badgeVariants = cva(
  "inline-flex items-center justify-center rounded-lg border px-1.5 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-0.5 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-all duration-300 overflow-hidden",
  {
    variants: {
      variant: {
        default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
        regular: "border-none",
        secondary:
          "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
        destructive:
          "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
        outline:
          "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground hover:bg-border/50",
        fancy:
          "bg-white dark:border-card dark:bg-background bg-radial-[at_40%_30%] shadow-md inset-shadow-sm shadow-shade inset-shadow-white/70 dark:inset-shadow-white/50 dark:inset-shadow-xs dark:to-transparent ",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  }
);

const colorVariantSets: Record<string, Record<Color, string>> = {
  fancy: colorVariantsFancy,
  regular: colorVariantsRegular,
  outline: colorVariantsOutline,
};

const dotVariants = cva("h-2 w-2 rounded-full mr-0.5", {
  variants: {
    color: {
      emerald: "bg-emerald-400",
      red: "bg-red-400",
      amber: "bg-amber-400",
      sky: "bg-sky-400",
      indigo: "bg-indigo-400",
      orange: "bg-orange-400",
      primary: "bg-primary/80",
    },
  },
});

function Badge({
  className,
  variant,
  asChild = false,
  color = "primary",
  showDot = false,
  children,
  ...props
}: React.ComponentProps<"span"> &
  VariantProps<typeof badgeVariants> & { asChild?: boolean; color?: Color; showDot?: boolean }) {
  const Comp = asChild ? Slot : "span";

  return (
    <Comp
      data-slot="badge"
      className={cn(
        badgeVariants({ variant }),
        colorVariantSets[variant || "default"]?.[color],
        className
      )}
      {...props}
    >
      {showDot && <div className={dotVariants({ color })}></div>}
      {children}
    </Comp>
  );
}

export { Badge, badgeVariants };
export type { Color };

More from asanshay

Browse all components in this library →