diff --git a/js/react/lib/components/badge/badge.component.tsx b/js/react/lib/components/badge/badge.component.tsx
new file mode 100644
index 0000000..85dd494
--- /dev/null
+++ b/js/react/lib/components/badge/badge.component.tsx
@@ -0,0 +1,34 @@
+import { withAs } from "@/utils/hoc";
+import { cn } from "@/utils/tw-merge";
+import {
+ BADGE_TEXT,
+ BADGE_TYPE,
+ BADGE_VARIANTS,
+ LIMIT_NUMERIC,
+} from "./badge.const";
+import { BadgeProps } from "./badge.types";
+
+export const Badge = withAs(
+ (Component, { type, variant, count, ...rest }: BadgeProps) => {
+ const displayValue = () => {
+ if (type !== "numeric") return BADGE_TEXT[variant];
+ if (count > LIMIT_NUMERIC) return `+${LIMIT_NUMERIC}`;
+ return count;
+ };
+
+ return (
+
+
+ {displayValue()}
+
+ );
+ }
+);
diff --git a/js/react/lib/components/badge/badge.const.ts b/js/react/lib/components/badge/badge.const.ts
new file mode 100644
index 0000000..a09de9d
--- /dev/null
+++ b/js/react/lib/components/badge/badge.const.ts
@@ -0,0 +1,35 @@
+export const BADGE_VARIANTS = {
+ completed: [
+ "bg-success-100 text-success-600 [&>div]:bg-success-600",
+ "dark:bg-success-950 dark:text-success-400 [&>div]:bg-success-600",
+ ],
+ reading: [
+ "bg-warning-100 text-warning-500 [&>div]:bg-warning-500",
+ "dark:bg-warning-950 dark:text-warning-300 [&>div]:bg-warning-300",
+ ],
+ pending: [
+ "bg-error-100 text-error-600 [&>div]:bg-error-600",
+ "dark:bg-error-950 dark:text-error-300 [&>div]:bg-error-300",
+ ],
+ unread: [
+ "bg-neutral-100 text-neutral-500 [&>div]:bg-neutral-500",
+ "dark:bg-neutral-950 dark:text-neutral-300 [&>div]:bg-neutral-300",
+ ],
+};
+
+export const BADGE_TYPE = {
+ default: "[&>span]:hidden size-4 px-0! justify-center",
+ numeric: "flex-row-reverse ",
+ text: undefined,
+};
+
+export const BADGE_TEXT = {
+ completed: "Completo",
+ reading: "Leyendo",
+ pending: "Pendiente",
+ unread: "No leĆdo",
+};
+
+export const LIMIT_NUMERIC = 9;
+export type BadgeVariants = keyof typeof BADGE_VARIANTS;
+export type BadgeTypes = keyof typeof BADGE_TYPE;
diff --git a/js/react/lib/components/badge/badge.types.ts b/js/react/lib/components/badge/badge.types.ts
new file mode 100644
index 0000000..4c02e00
--- /dev/null
+++ b/js/react/lib/components/badge/badge.types.ts
@@ -0,0 +1,13 @@
+import { BadgeTypes, BadgeVariants } from "./badge.const";
+
+export type BadgeProps =
+ | {
+ type: Extract;
+ variant: BadgeVariants;
+ count: number;
+ }
+ | {
+ type: Exclude;
+ variant: BadgeVariants;
+ count?: never;
+ };
diff --git a/js/react/lib/components/badge/index.ts b/js/react/lib/components/badge/index.ts
new file mode 100644
index 0000000..f2ee33c
--- /dev/null
+++ b/js/react/lib/components/badge/index.ts
@@ -0,0 +1,2 @@
+export * from "./badge.component";
+export * from "./badge.types";
diff --git a/js/react/lib/index.ts b/js/react/lib/index.ts
index edaf843..927f19e 100644
--- a/js/react/lib/index.ts
+++ b/js/react/lib/index.ts
@@ -7,4 +7,5 @@ export * from "./components/level";
export * from "./components/avatar";
export * from "./components/collaborators";
export * from "./components/radio";
+export * from "./components/badge";
export * from "./icons";
diff --git a/js/react/showcase/App.tsx b/js/react/showcase/App.tsx
index 3b7bd5c..e922c5d 100644
--- a/js/react/showcase/App.tsx
+++ b/js/react/showcase/App.tsx
@@ -9,6 +9,7 @@ import {
Level,
Collaborators,
Radio,
+ Badge,
} from "@rustlanges/react";
import { ShowComponent } from "./ShowComponent";
@@ -219,6 +220,28 @@ export function App() {
},
}}
/>
+
);
}