Tag

Data Display
Interactive

Removable labels for categorization, filtering, and selections. Interactive alternative to static badges.

Preview

Interactive tag examples

ReactTypeScriptNext.jsTailwind

Variants

All available tag styles

DefaultPrimarySecondarySuccessWarningErrorInfoVioletOutline

Sizes

Available tag sizes

SmallMediumLarge

With Icons

Tags with leading icons

VerifiedFeaturedPremiumTrending

Removable Tags

Tags that can be removed

DefaultPrimarySuccessError

Click the X button to trigger the onRemove callback.

Clickable Tags

Tags as toggleable filters

DesignDevelopmentMarketingSales

Selected: Design

Disabled State

Disabled tags for read-only display

DisabledNot RemovableNot Clickable

With Truncation

Tags with max width for long labels

Very Long Tag Label That Gets TruncatedAnother Long Label Here

Use Cases

Common tag patterns

Email Labels

UrgentWorkPersonalFollow-up

Skills/Technologies

javascriptreacttypescriptnode

Status Indicators

CompletedIn ReviewBlockedDraft

Props

Tag component API reference

PropTypeDefaultDescription
variant'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | 'violet' | 'outline''default'Visual style variant for the tag
size'sm' | 'md' | 'lg''md'Size of the tag
iconReact.ReactNodeOptional icon to display before the label
removablebooleanfalseWhether the tag shows a remove button
onRemove() => voidCallback when the remove button is clicked
clickablebooleanfalseWhether the tag is clickable
onClick() => voidCallback when the tag is clicked (requires clickable=true)
disabledbooleanfalseWhether the tag is disabled
maxWidthstring | numberMax width for truncation
classNamestringAdditional CSS classes for custom styling

Usage

Import and implementation example

import { Tag } from '@/components/ui/tag'

export default function Example() {
  const [tags, setTags] = useState(['React', 'TypeScript', 'Next.js'])

  const removeTag = (tagToRemove: string) => {
    setTags(tags.filter(tag => tag !== tagToRemove))
  }

  return (
    <div className="flex flex-wrap gap-2">
      {tags.map(tag => (
        <Tag
          key={tag}
          variant="primary"
          removable
          onRemove={() => removeTag(tag)}
        >
          {tag}
        </Tag>
      ))}
    </div>
  )
}

Features

Built-in functionality

  • 9 variants: Default, primary, secondary, success, warning, error, info, violet, and outline styles
  • 3 sizes: Small, medium, and large sizes
  • Removable: Optional X button with onRemove callback
  • Clickable: Can function as toggleable filter buttons
  • Icon support: Optional leading icon
  • Truncation: Max width option for long labels
  • Disabled state: Visual and interaction disabled state
  • Dark mode: Full dark mode support with proper color contrast

Accessibility

ARIA support and keyboard navigation

ARIA Attributes

role="button" (when clickable)aria-disabled (when disabled)aria-label (on remove button)

Keyboard Navigation

KeyAction
TabMove focus to tag (when clickable) or remove button
Enter / SpaceActivate tag click or remove action

Notes

  • Clickable tags are keyboard accessible with Enter/Space activation
  • Remove buttons have descriptive aria-labels including tag content
  • Disabled state prevents both mouse and keyboard interaction
  • Focus indicators are visible on interactive elements