Build websites 10x faster with HextaUI Blocks — Learn more
UI/UI

Chip

A compact, interactive element for displaying status, categories, or filters with optional icons and dismissible functionality.

Default
Secondary
Outline
Ghost
Destructive
<div className="flex gap-4 flex-wrap">
  <Chip>Default</Chip>
  <Chip variant="secondary">Secondary</Chip>
  <Chip variant="outline">Outline</Chip>
  <Chip variant="ghost">Ghost</Chip>
  <Chip variant="destructive">Destructive</Chip>
</div>

Installation

Install following dependencies:

npm install class-variance-authority lucide-react
pnpm add class-variance-authority lucide-react
yarn add class-variance-authority lucide-react
bun add class-variance-authority lucide-react

Copy and paste the following code into your project.

components/ui/chip.tsx
"use client";

import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import { type LucideIcon, X } from "lucide-react";

const chipVariants = cva(
  "inline-flex items-center justify-center rounded-full border text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
  {
    variants: {
      variant: {
        default:
          "border-transparent bg-[hsl(var(--hu-primary))] text-[hsl(var(--hu-primary-foreground))] hover:bg-[hsl(var(--hu-primary))]/80 focus-visible:ring-[hsl(var(--hu-ring))]",
        secondary:
          "border-transparent bg-[hsl(var(--hu-secondary))] text-[hsl(var(--hu-secondary-foreground))] hover:bg-[hsl(var(--hu-secondary))]/80 focus-visible:ring-[hsl(var(--hu-ring))]",
        destructive:
          "border-transparent bg-[hsl(var(--hu-destructive))] text-[hsl(var(--hu-destructive-foreground))] hover:bg-[hsl(var(--hu-destructive))]/80 focus-visible:ring-[hsl(var(--hu-destructive))]",
        outline:
          "border-[hsl(var(--hu-border))] text-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-accent))] hover:text-[hsl(var(--hu-accent-foreground))] focus-visible:ring-[hsl(var(--hu-ring))]",
        ghost:
          "border-transparent text-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-accent))] hover:text-[hsl(var(--hu-accent-foreground))] focus-visible:ring-[hsl(var(--hu-ring))]",
      },
      size: {
        sm: "h-6 px-2 gap-1 text-xs",
        default: "h-7 px-3 gap-1.5 text-sm",
        lg: "h-8 px-4 text-sm gap-2",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  },
);

export interface ChipProps
  extends React.HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof chipVariants> {
  icon?: LucideIcon;
  iconPosition?: "left" | "right";
  dismissible?: boolean;
  onDismiss?: () => void;
}

const Chip = React.forwardRef<HTMLDivElement, ChipProps>(
  (
    {
      className,
      variant,
      size,
      icon: Icon,
      iconPosition = "left",
      dismissible = false,
      onDismiss,
      children,
      ...props
    },
    ref,
  ) => {
    const iconSize = size === "sm" ? 12 : size === "lg" ? 14 : 12;
    const closeIconSize = size === "sm" ? 10 : size === "lg" ? 12 : 10;

    const handleDismiss = (e: React.MouseEvent) => {
      e.stopPropagation();
      onDismiss?.();
    };

    return (
      <div
        ref={ref}
        className={cn(chipVariants({ variant, size }), className)}
        {...props}
      >
        {Icon && iconPosition === "left" && (
          <Icon size={iconSize} className="shrink-0" />
        )}
        {children}
        {Icon && iconPosition === "right" && !dismissible && (
          <Icon size={iconSize} className="shrink-0" />
        )}
        {dismissible && (
          <button
            type="button"
            onClick={handleDismiss}
            className="ml-1 shrink-0 rounded-full p-0.5 hover:bg-black/10 dark:hover:bg-white/10 transition-colors"
            aria-label="Remove"
          >
            <X size={closeIconSize} />
          </button>
        )}
      </div>
    );
  },
);

Chip.displayName = "Chip";

export { Chip, chipVariants };
npx hextaui@latest add chip
pnpm dlx hextaui@latest add chip
yarn dlx hextaui@latest add chip
bun x hextaui@latest add chip

Usage

import { Chip } from "@/components/ui/Chip";
<Chip variant="default">Default Chip</Chip>
<Chip variant="secondary">Secondary Chip</Chip>
<Chip variant="outline">Outline Chip</Chip>
<Chip variant="ghost">Ghost Chip</Chip>
<Chip variant="destructive">Destructive Chip</Chip>

Examples

Variants

Default
Secondary
Outline
Ghost
Destructive
<div className="flex gap-4 flex-wrap">
  <Chip variant="default">Default</Chip>
  <Chip variant="secondary">Secondary</Chip>
  <Chip variant="outline">Outline</Chip>
  <Chip variant="ghost">Ghost</Chip>
  <Chip variant="destructive">Destructive</Chip>
</div>

Sizes

Small
Default
Large
<div className="flex gap-4 flex-wrap items-center">
  <Chip size="sm">Small</Chip>
  <Chip size="default">Default</Chip>
  <Chip size="lg">Large</Chip>
</div>

With Icons

Category

Member

Featured

Premium

Warning

import { Tag, User, Star, Shield, AlertTriangle } from "lucide-react";

<div className="flex gap-4 flex-wrap">
  <Chip icon={Tag} variant="default">
    Category
  </Chip>
  <Chip icon={User} variant="secondary" iconPosition="left">
    Member
  </Chip>
  <Chip icon={Star} variant="outline">
    Featured
  </Chip>
  <Chip icon={Shield} variant="ghost">
    Premium
  </Chip>
  <Chip icon={AlertTriangle} variant="destructive">
    Warning
  </Chip>
</div>

Icon Positions

Next

Continue

Email

Call

import { ArrowRight, Mail, Phone } from "lucide-react";

<div className="flex gap-4 flex-wrap">
  <Chip icon={ArrowRight} variant="default" iconPosition="left">
    Next
  </Chip>
  <Chip icon={ArrowRight} variant="secondary" iconPosition="right">
    Continue
  </Chip>
  <Chip icon={Mail} variant="outline" iconPosition="left">
    Email
  </Chip>
  <Chip icon={Phone} variant="ghost" iconPosition="right">
    Call
  </Chip>
</div>

Dismissible Chips

Remove me
JavaScript
John Doe
Error
import { Tag, User } from "lucide-react";

<div className="flex gap-4 flex-wrap">
  <Chip dismissible onDismiss={() => alert("Chip dismissed!")}>
    Remove me
  </Chip>
  <Chip
    icon={Tag}
    variant="secondary"
    dismissible
    onDismiss={() => alert("Tag removed!")}
  >
    JavaScript
  </Chip>
  <Chip
    icon={User}
    variant="outline"
    dismissible
    onDismiss={() => alert("User removed!")}
  >
    John Doe
  </Chip>
  <Chip variant="destructive" dismissible size="sm">
    Error
  </Chip>
</div>

Filter Tags

Technologies

React
TypeScript
Next.js
Tailwind

Team Members

Alice
Bob
Charlie
import { Tag, User } from "lucide-react";

<div className="space-y-4">
  <div>
    <h4 className="text-sm font-medium mb-2">Technologies</h4>
    <div className="flex gap-2 flex-wrap">
      <Chip icon={Tag} variant="outline" dismissible>React</Chip>
      <Chip icon={Tag} variant="outline" dismissible>TypeScript</Chip>
      <Chip icon={Tag} variant="outline" dismissible>Next.js</Chip>
      <Chip icon={Tag} variant="outline" dismissible>Tailwind</Chip>
    </div>
  </div>
  <div>
    <h4 className="text-sm font-medium mb-2">Team Members</h4>
    <div className="flex gap-2 flex-wrap">
      <Chip icon={User} variant="secondary" size="sm" dismissible>Alice</Chip>
      <Chip icon={User} variant="secondary" size="sm" dismissible>Bob</Chip>
      <Chip icon={User} variant="secondary" size="sm" dismissible>Charlie</Chip>
    </div>
  </div>
</div>

Status Indicators

Pending
In Progress
Completed
Failed
import { Clock, CheckCircle, Check, X } from "lucide-react";

<div className="flex gap-4 flex-wrap">
  <Chip icon={Clock} variant="ghost">Pending</Chip>
  <Chip icon={CheckCircle} variant="secondary">In Progress</Chip>
  <Chip icon={Check} variant="default">Completed</Chip>
  <Chip icon={X} variant="destructive">Failed</Chip>
</div>

Contact Information

+1 (555) 123-4567

San Francisco, CA

import { Mail, Phone, MapPin, Globe } from "lucide-react";

<div className="space-y-3">
  <div className="flex gap-2 flex-wrap">
    <Chip icon={Mail} variant="outline" size="sm">
      john@example.com
    </Chip>
    <Chip icon={Phone} variant="outline" size="sm">
      +1 (555) 123-4567
    </Chip>
  </div>
  <div className="flex gap-2 flex-wrap">
    <Chip icon={MapPin} variant="ghost" size="sm">
      San Francisco, CA
    </Chip>
    <Chip icon={Globe} variant="ghost" size="sm">
      www.example.com
    </Chip>
  </div>
</div>

Interactive Chips

Clickable
Like
Focusable
Add Filter
import { Heart, Plus } from "lucide-react";

<div className="flex gap-4 flex-wrap">
  <Chip className="cursor-pointer" onClick={() => alert("Chip clicked!")}>
    Clickable
  </Chip>
  <Chip
    icon={Heart}
    variant="outline"
    className="cursor-pointer hover:bg-red-50 hover:border-red-300 hover:text-red-600"
    onClick={() => alert("Like clicked!")}
  >
    Like
  </Chip>
  <Chip variant="secondary" className="cursor-pointer" tabIndex={0}>
    Focusable
  </Chip>
  <Chip
    icon={Plus}
    variant="ghost"
    className="cursor-pointer"
    onClick={() => alert("Add clicked!")}
  >
    Add Filter
  </Chip>
</div>

Real-world Examples

Product Tags

New
Bestseller
Sale
Limited

Selected Filters

Price: $50-100
Brand: Nike
Color: Blue
Size: Medium

Event Attendees

Sarah Wilson
Mike Johnson
Anna Davis
+5 more
import { Award, Star, Tag, User } from "lucide-react";

<div className="space-y-6">
  <div>
    <h4 className="text-sm font-medium mb-3">Product Tags</h4>
    <div className="flex gap-2 flex-wrap">
      <Chip icon={Award} variant="default" size="sm">New</Chip>
      <Chip icon={Star} variant="secondary" size="sm">Bestseller</Chip>
      <Chip icon={Tag} variant="outline" size="sm">Sale</Chip>
      <Chip variant="destructive" size="sm">Limited</Chip>
    </div>
  </div>

  <div>
    <h4 className="text-sm font-medium mb-3">Selected Filters</h4>
    <div className="flex gap-2 flex-wrap">
      <Chip variant="outline" dismissible>Price: $50-100</Chip>
      <Chip variant="outline" dismissible>Brand: Nike</Chip>
      <Chip variant="outline" dismissible>Color: Blue</Chip>
      <Chip variant="outline" dismissible>Size: Medium</Chip>
    </div>
  </div>

  <div>
    <h4 className="text-sm font-medium mb-3">Event Attendees</h4>
    <div className="flex gap-2 flex-wrap">
      <Chip icon={User} variant="secondary" size="sm" dismissible>
        Sarah Wilson
      </Chip>
      <Chip icon={User} variant="secondary" size="sm" dismissible>
        Mike Johnson
      </Chip>
      <Chip icon={User} variant="secondary" size="sm" dismissible>
        Anna Davis
      </Chip>
      <Chip variant="ghost" size="sm" className="cursor-pointer">
        +5 more
      </Chip>
    </div>
  </div>
</div>

Props

PropTypeDefault
children?
ReactNode
undefined
className?
string
undefined
onDismiss?
() => void
undefined
dismissible?
boolean
false
iconPosition?
"left" | "right"
"left"
icon?
LucideIcon
undefined
size?
"sm" | "default" | "lg"
"default"
variant?
"default" | "secondary" | "destructive" | "outline" | "ghost"
"default"
Edit on GitHub

Last updated on