npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@codav/tag-input

v1.0.2

Published

A customizable React tag input component with comma and Enter parsing

Downloads

62

Readme

@codav/tag-input

A powerful, customizable, TypeScript-first React Tag Input component with keyboard support, comma parsing, RTL/LTR support, duplicate prevention, and flexible styling.

npm version npm downloads npm license GitHub stars GitHub issues TypeScript React


✨ Overview

@codav/tag-input is a lightweight, reusable, and highly customizable React Tag Input component built with TypeScript.

It provides a modern input experience for creating, managing, and removing tags using:

  • Enter
  • Comma (, )
  • Backspace
  • Optional action button
  • Blur-to-add behavior

The component is designed to work naturally with React, Next.js, TypeScript, admin dashboards, CMS platforms, forms, blogs, e-commerce applications, and modern design systems.


🚀 Why @codav/tag-input?

Building a good tag input sounds simple until you need:

  • Keyboard interactions
  • Duplicate prevention
  • Maximum tag limits
  • RTL support
  • Custom tag rendering
  • Custom styling
  • Controlled state
  • Accessibility
  • Next.js compatibility
  • Clean TypeScript types

@codav/tag-input provides these capabilities in a single reusable component.


🎯 Features

  • ⚡ Lightweight React component
  • 🔷 TypeScript-first
  • ⚛️ React 18+ compatible
  • ▲ Next.js compatible
  • ⌨️ Enter-to-add
  • , comma-to-add
  • ⌫ Backspace-to-remove
  • 🖱️ Optional add button
  • 🔄 Add multiple tags at once
  • 🚫 Duplicate prevention
  • 🔢 Maximum tag limit
  • 🧩 Custom tag renderer
  • 🎨 Highly customizable styling
  • 🌐 RTL / LTR / Auto direction
  • ♿ Keyboard-friendly interaction
  • 🧱 Controlled component API
  • 🪶 Small production build
  • 📦 ESM + CommonJS
  • 🔌 Easy integration
  • 🌙 Tailwind-friendly
  • 🛠️ Standard HTML input attributes

📦 Installation

npm install @codav/tag-input

Using legacy peer dependency resolution:

npm install @codav/tag-input --legacy-peer-deps

⚡ Quick Start

"use client";

import { useState } from "react";
import { Tag } from "lucide-react";
import { TagInput } from "@codav/tag-input";

export default function Example() {
  const [tags, setTags] = useState<string[]>([]);

  return (
    <TagInput
      label="Tags"
      value={tags}
      onChange={setTags}
      placeholder="Type a tag and press Enter..."
      icon={Tag}
    />
  );
}

🇮🇷 Persian / RTL Example

"use client";

import { useState } from "react";
import { Tag } from "lucide-react";
import { TagInput } from "@codav/tag-input";

export default function PersianTags() {
  const [tags, setTags] = useState<string[]>([]);

  return (
    <TagInput
      label="برچسب‌ها"
      description="برچسب‌ها را با کاما یا Enter اضافه کنید"
      value={tags}
      onChange={setTags}
      placeholder="مثلاً Laravel، React، Next.js"
      icon={Tag}
      direction="rtl"
    />
  );
}

⌨️ Keyboard Interaction

The component is designed around fast keyboard interaction.

| Action | Result | |---|---| | Enter | Add current input as a tag | | , | Parse and add tags | | Backspace | Remove the last tag when input is empty | | Blur | Optionally add current input |

Example:

Laravel

Press:

Enter

Result:

["Laravel"]

🏷️ Multiple Tags

You can enter multiple comma-separated values:

Laravel, React, Next.js, TypeScript

The component converts them into:

[
  "Laravel",
  "React",
  "Next.js",
  "TypeScript"
]

🎨 Custom Styling

One of the main goals of this package is styling flexibility.

You can customize:

  • Wrapper
  • Input
  • Tags
  • Remove buttons
  • Action button
  • Custom rendered tags

Example:

<TagInput
  value={tags}
  onChange={setTags}
  wrapperClassName="space-y-2"
  inputClassName="font-medium"
  tagClassName="rounded-full bg-primary/10 text-primary"
  tagRemoveClassName="hover:bg-red-500 hover:text-white"
  buttonClassName="rounded-full"
/>

🧩 Custom Tag Rendering

For complete control over the tag UI, use renderTag.

<TagInput
  value={tags}
  onChange={setTags}
  renderTag={(tag, index, remove) => (
    <button
      type="button"
      onClick={remove}
      className="rounded-full bg-black px-3 py-1 text-sm text-white"
    >
      {tag}
    </button>
  )}
/>

The callback receives:

(
  tag: string,
  index: number,
  remove: () => void
) => ReactNode

This makes it possible to create completely custom tag designs.


🔢 Maximum Tags

Limit the number of tags:

<TagInput
  value={tags}
  onChange={setTags}
  maxTags={10}
/>

Once the limit is reached, additional tags are ignored.


🚫 Duplicate Prevention

Duplicate tags are prevented by default.

<TagInput
  value={tags}
  onChange={setTags}
/>

For example:

React
react
REACT

are treated as duplicates.

To allow duplicates:

<TagInput
  value={tags}
  onChange={setTags}
  allowDuplicates
/>

🔧 Custom Separator

The default separator is:

,

You can customize it:

<TagInput
  value={tags}
  onChange={setTags}
  separator=";"
/>

Now:

Laravel;React;Next.js

becomes:

[
  "Laravel",
  "React",
  "Next.js"
]

🖱️ Add on Blur

By default, the component can add the current input when the field loses focus.

<TagInput
  value={tags}
  onChange={setTags}
  addOnBlur
/>

Disable it:

<TagInput
  value={tags}
  onChange={setTags}
  addOnBlur={false}
/>

🌐 RTL / LTR

RTL:

<TagInput
  direction="rtl"
  value={tags}
  onChange={setTags}
/>

LTR:

<TagInput
  direction="ltr"
  value={tags}
  onChange={setTags}
/>

Automatic:

<TagInput
  direction="auto"
  value={tags}
  onChange={setTags}
/>

🧱 Controlled State

TagInput is a fully controlled component.

const [tags, setTags] = useState<string[]>([]);

<TagInput
  value={tags}
  onChange={setTags}
/>

Your application remains responsible for the actual tag data.


🛑 Disabled State

<TagInput
  value={tags}
  onChange={setTags}
  disabled
/>

When disabled:

  • Input is disabled
  • Tags cannot be removed
  • New tags cannot be added
  • Action button is disabled

❌ Error State

<TagInput
  label="Tags"
  value={tags}
  onChange={setTags}
  error="Please add at least one tag."
/>

🏷️ Labels and Descriptions

<TagInput
  label="Technologies"
  description="Add technologies used in this project."
  value={tags}
  onChange={setTags}
/>

🧑‍💻 Real-World Example

"use client";

import { useState } from "react";
import { Tag } from "lucide-react";
import { TagInput } from "@codav/tag-input";

export default function ProjectTags() {
  const [tags, setTags] = useState<string[]>([]);

  return (
    <div className="space-y-6">
      <TagInput
        label="Project Technologies"
        description="Add technologies using comma or Enter."
        value={tags}
        onChange={setTags}
        placeholder="Laravel, React, Next.js..."
        icon={Tag}
        direction="ltr"
        maxTags={20}
      />

      <pre>
        {JSON.stringify(tags, null, 2)}
      </pre>
    </div>
  );
}

📚 API

TagInputProps

export type TagInputProps = {
  value: string[];

  onChange: (
    tags: string[]
  ) => void;

  label?: string;

  description?: string;

  error?: string;

  icon?: ComponentType<{
    className?: string;
  }>;

  separator?: string;

  addOnBlur?: boolean;

  allowDuplicates?: boolean;

  maxTags?: number;

  direction?:
    | "ltr"
    | "rtl"
    | "auto";

  generateButton?: boolean;

  generateButtonLabel?: string;

  wrapperClassName?: string;

  inputClassName?: string;

  tagClassName?: string;

  tagRemoveClassName?: string;

  buttonClassName?: string;

  renderTag?: (
    tag: string,
    index: number,
    remove: () => void
  ) => ReactNode;
};

The component also supports standard HTML input attributes.


▲ Next.js Support

@codav/tag-input works with the Next.js App Router.

Because the component uses client-side React state and browser events, import it from a Client Component:

"use client";

import { TagInput } from "@codav/tag-input";

🔷 TypeScript

The package is written in TypeScript and is designed for TypeScript projects.

import {
  TagInput,
  type TagInputProps,
} from "@codav/tag-input";

📦 Build Output

The package generates modern ESM and CommonJS builds.

dist/
├── index.mjs
├── index.js
├── index.mjs.map
└── index.js.map

🛠️ Development

Clone the repository:

git clone https://github.com/MohammadMahdiAhmadi1382/react-tag-input.git

Enter the project:

cd react-tag-input

Install dependencies:

npm install

Run the production build:

npm run build

📁 Project Structure

react-tag-input/
│
├── src/
│   ├── index.ts
│   ├── types.ts
│   └── TagInput.tsx
│
├── dist/
│   ├── index.js
│   ├── index.mjs
│   ├── index.js.map
│   └── index.mjs.map
│
├── package.json
├── tsconfig.json
├── tsup.config.ts
├── README.md
└── LICENSE

🧠 Design Principles

Minimal API

The simplest implementation only requires:

<TagInput
  value={tags}
  onChange={setTags}
/>

Application-Owned State

The component does not manage your final tag collection.

Your application owns the data.

Flexible UI

The package does not force a specific design system.

Style hooks allow the component to adapt to existing applications.

Keyboard First

Fast data entry is a core feature.

Enter      → Add
Comma      → Add
Backspace  → Remove

Framework Friendly

Designed for:

  • React
  • Next.js
  • TypeScript
  • Admin panels
  • CMS
  • SaaS dashboards
  • E-commerce
  • CRM
  • Blogs
  • Forms
  • Search interfaces

💡 Use Cases

@codav/tag-input can be used for:

  • Blog tags
  • Article keywords
  • SEO keywords
  • Product tags
  • Product attributes
  • Search filters
  • User interests
  • Skills
  • Technologies
  • Categories
  • Project labels
  • Course tags
  • Student skills
  • Content metadata
  • Permissions
  • Email recipients
  • Feature lists
  • CMS metadata

🔌 Dependencies

The package uses:

  • React
  • React DOM
  • clsx
  • lucide-react

The component does not depend on application-specific UI components.


🌍 Browser Target

The package targets:

ES2020

and is intended for modern browsers and JavaScript environments.


📈 Performance

The component is designed to remain lightweight and dependency-conscious.

The production package contains only the generated distribution files required by consumers.


🤝 Contributing

Contributions are welcome.

Before creating a pull request:

npm install
npm run build

Please ensure the package builds successfully.

For bug reports, include:

  • Package version
  • React version
  • Next.js version if applicable
  • Browser
  • Operating system
  • Reproduction steps
  • Expected behavior
  • Actual behavior

🐛 Issues & Feature Requests

Found a bug or have an idea?

Open an issue in the GitHub repository:

https://github.com/MohammadMahdiAhmadi1382/react-tag-input/issues

Please provide enough information to reproduce the problem.


📜 License

MIT License

Copyright (c) Mohammad Mahdi Ahmadi / CODAVO

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software.

The software is provided "as is", without warranty of any kind.


👨‍💻 Author

Mohammad Mahdi Ahmadi

Full-Stack Developer & Software Engineer

GitHub:

https://github.com/MohammadMahdiAhmadi1382


🏢 CODAVO

Part of the reusable frontend and developer tooling ecosystem developed by CODAVO.

The goal is to build clean, reusable, production-oriented packages that can be integrated into modern web applications with minimal configuration.


🔗 Links

GitHub Repository

https://github.com/MohammadMahdiAhmadi1382/react-tag-input

NPM Package

https://www.npmjs.com/package/@codav/tag-input

Author

https://github.com/MohammadMahdiAhmadi1382


⭐ Support

If this package is useful to you, consider giving the repository a ⭐ on GitHub.

Your feedback, issues, and contributions help improve the project.


Keywords

react reactjs react-component tag-input tags-input input-component typescript nextjs next.js npm ui-component form-component form-input multi-input multi-value-input chips-input token-input keyword-input react-tags tag-editor rtl ltr tailwindcss frontend web-development codav