About
A small rounded label for a status or tag that can optionally be toggled (selected/pressed) or dismissed with a built-in remove button.
Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Chip to your project and fits it to your theme.
Code
How Chip is used: the demo's code. The component's own source comes with a free account.
Usage.tsx
import Chip from "@/components/ui/chip";
import { useState } from "react";
const invoices = [
{ number: "2026-0141", status: "unpaid" },
{ number: "2026-0142", status: "overdue" },
{ number: "2026-0143", status: "paid" },
{ number: "2026-0144", status: "unpaid" },
{ number: "2026-0145", status: "paid" },
];
const statuses = [
{ label: "Unpaid", value: "unpaid" },
{ label: "Overdue", value: "overdue" },
{ label: "Paid", value: "paid" },
];
export default function Filter() {
const [selected, setSelected] = useState(["unpaid", "overdue"]);
const shown = invoices.filter((invoice) => selected.includes(invoice.status));
return (
<div className="space-y-3">
<div aria-label="Status" className="flex flex-wrap gap-2" role="group">
{statuses.map((status) => (
<Chip
color="primary"
key={status.value}
onSelectedChange={(isSelected) =>
setSelected((current) =>
isSelected
? [...current, status.value]
: current.filter((value) => value !== status.value),
)
}
selected={selected.includes(status.value)}
>
{status.label}
</Chip>
))}
</div>
<p className="text-sm text-neutral-600 dark:text-neutral-400">
{shown.length} of {invoices.length} invoices:{" "}
{shown.map((invoice) => invoice.number).join(", ") || "none"}
</p>
</div>
);
}
