Tag Box

A versatile component for managing and displaying tags with rich customization options.

Popover API Reference
Inspired by Fancy Box (mxkaske)

Playground

Customize the Tag Box properties to see different variations.

Standard Usage

This example demonstrates the TagBox with Radix UI Popover for positioning. The dropdown will be correctly positioned and not clipped by parent containers.

Customize

Installation

pnpm dlx shadcn@latest add https://shadcn-ui-variants.vercel.app/r/tag-box.json

Overview

The TagBox component offers a robust and user-friendly solution for managing tags within your application. It empowers users to effortlessly add, select, remove, and edit tags, complete with suggestions, customizable appearances, and flexible state management options (controlled and uncontrolled). It's designed to integrate seamlessly with your UI, leveraging components like Badges, Popovers, and Modals for a rich interactive experience.

Features

  • Tag Input: Add tags by typing or selecting from a dynamic list of suggestions.
  • Tag Creation: Dynamically create new tags if they don't exist in the predefined list.
  • Tag Removal: Easily remove selected tags with a single click on the 'x' icon.
  • Tag Management Interface: A built-in modal allows users to edit tag names and colors (if enabled) for all known tags.
  • Color Customization: Assign distinct colors to tags for better visual organization. This feature can be globally toggled using the withColor prop.
  • Controlled and Uncontrolled Modes: Flexible state management. Use it as a controlled component by providing value and onChange props, or as an uncontrolled component with defaultValue.
  • Max Tags Limit: Set a maximum number of selectable tags, with visual feedback when the limit is reached.
  • Customizable Placeholders: Define custom placeholder text for the input field.
  • Styling: Leverages Badge component for tag display, allowing easy styling via inherited props or custom class names (className, tagClassName).
  • Accessibility: Built with Radix UI primitives, focusing on accessibility and keyboard navigation.

Basic Usage

Import the TagBox component and, optionally, the TagType for typing your tag data.

import { TagBox, type TagType } from "@/components/tag-box"
<TagBox userTags={availableUserTags} />

For a minimal setup, you can provide an array of userTags which are the predefined tags available for selection and management.

Controlled vs. Uncontrolled Mode

TagBox can operate in two modes:

  1. Controlled Mode: You manage the state of selected tags. Provide the value prop (an array of selected TagType objects) and handle updates via the onChange callback. This gives you full control over the tag selection state.
    const [selectedTags, setSelectedTags] = React.useState<TagType[]>([]); <TagBox userTags={allMyTags} value={selectedTags} onChange={setSelectedTags} />
  2. Uncontrolled Mode: The component manages its own selection state internally. You can provide a defaultValue prop for the initial set of selected tags. You can still listen to changes using the onChange callback if needed. This mode is simpler for basic use cases.
    <TagBox userTags={allMyTags} defaultValue={[{ id: "1", name: "Initial Tag" }]} onChange={(tags) => console.log("Tags changed:", tags)} />

Tag Management Callbacks

The "Manage tags" dialog allows users to modify the global list of available tags. To persist these changes, use the onTagEdit and onTagRemove callbacks:

  • onTagEdit: Called when a tag's name or color is saved in the management dialog. You should update your master list ofuserTags (e.g., in your state or database) with the received updated tag object.
  • onTagRemove: Called when a tag is deleted from the management dialog. You should remove this tag from your master list of userTags.

Properly handling these callbacks ensures that changes made in the "Manage tags" dialog are reflected globally and persist as needed.

Examples

With Maximum Tags Limit & Uncontrolled

Demonstrates limiting the number of selectable tags with a visual indicator, used in an uncontrolled manner with a default value.

React
Next.js
TypeScript

Custom Styling & Inner Tags

Customize the appearance of the TagBox and its tags.

Controlled Mode & Form Integration

Illustrates using TagBox as a controlled component within a form, managing its state and potentially integrating with form validation.

Create New Task
Fill in the details below to create a new task.

Tag Management & Real-time Filtering

An advanced example showing how to handle onTagEdit and onTagRemove to manage userTags, and using selected tags to filter a list of items in real-time. Tag editing and creation are disabled.

Filter Tasks by Tags:

Fix navigation menu
Frontend
Bug
Implement authentication
Backend
Feature
Add dark mode
Frontend
Feature
Fix API response format
Backend
Bug

Badge Props Integration

The TagBox component renders each selected tag using an internal Badge component. You can directly pass props supported by the Badge component (such as variant, size, shape, leftElement, rightElement) to the TagBox. These props will be applied to each individual tag badge. For example, to change the shape of all tags:

<TagBox userTags={userTags} shape="square" />

Refer to the Badge component documentation for a full list of available props and their effects. The tagClassName prop can also be used for more specific CSS customization of the badges.

Notes and Best Practices

  • Unique Tag IDs: While not strictly enforced for basic operation if only names are used, providing unique id fields in your TagType objects is highly recommended, especially for stable keying, reliable editing, and removal when tag names might not be unique or could change. The component will generate a temporary random ID for newly created tags if an ID is not part of the `existingUserTag` or implicitly handled by your `onTagEdit` logic for new tags.
  • State Management for userTags: The userTags prop provides the initial set of available tags. If you allow tag creation or editing through the "Manage Tags" dialog, you are responsible for updating your source userTags array using the onTagEdit and onTagRemove callbacks to ensure consistency.
  • Performance: For very large sets of userTags or selected tags, consider performance implications. Virtualization for the suggestion list is not built-in but could be a custom enhancement if needed.
  • Styling Conflicts: Be mindful of CSS specificity if applying extensive custom styles, especially when using className and tagClassName alongside inherited Badge props.

TagBox Props

PropTypeDefault
value
TagType[]
defaultValue
TagType[]
onChange
function
name
string
userTags
TagType[]
onTagEdit
function
onTagRemove
function
maxTags
number
showMaxTags
booleanfalse
placeholder
string"Type or select tags..."
placeholderWhenFull
string"Max tags reached"
className
string
tagClassName
string
withColor
booleantrue
openOnFocus
booleantrue
enableCreate
booleantrue
enableManage
booleantrue
tagsPosition
enum"bottom"
disabled
booleanfalse