Simple tag input for Bootstrap

  • By Erwin Heldy G
  • Last update: Sep 28, 2022
  • Comments: 10


Simple tag input for Bootstrap. Supports bootstrap v4 and v5.



  • Custom separators
  • Enable/disable duplicates
  • Custom transform
  • Supports Bootstrap validation style
  • Fast
  • Small
  • No dependencies


Install tagin with npm:

npm install tagin

Install from cdn:

<link rel="stylesheet" href="[email protected]/dist/tagin.min.css">
<script src="[email protected]/dist/tagin.min.js"></script>


Place css between <head></head> tags:

    <link rel="stylesheet" href="[email protected]/dist/tagin.min.css">

Place js before </body> tag:

    <script src="[email protected]/dist/tagin.min.js"></script>
  • You can also use tagin as javascript module:
<script src="yourscript.js" type="module"></script>

In yourscript.js file, import Tagin (Change location according to your path):

import Tagin from './path/to/tagin.module.js'

Or you can use it directly in the html script as a module:

<script type="module">
	import Tagin from './path/to/tagin.module.js'

1. Basic Usage (No data-options attribute needed):

<input type="text" name="tags" class="form-control tagin" value="red,green,blue">
const options = {
    separator: ',', // default: ','
    duplicate: false, // default: false
    enter: true, // default: false
    transform: 'input => input.toUpperCase()', // default: input => input
    placeholder: 'Add a group...' // default: ''
const tagin = new Tagin(document.querySelector('.tagin'), options)

tagin.addTag('yellow') // Add tag 'yellow'
tagin.addTag(['cyan', 'black']) // Add tags 'cyan' and 'black'
tagin.getTag() // Return tags as string red,green,blue,yellow,cyan,black
tagin.getTags() // Return tags as array ['red', 'green', 'blue', 'yellow', 'cyan', 'black']

2. Using Placeholder

Using data-tagin-placeholder attribute:

<input type="text" name="tags" class="form-control tagin" value="red,green,blue" data-tagin-placeholder="Add a color... (then press comma)">

Or using option:

const tagin = new Tagin(document.querySelector('.tagin'), {
  placeholder: 'Add a color... (then press comma)'

3. Using Custom Separator

Example tags with 'space' separator. Using data-tagin-separator attribute:

<input type="text" name="tags" class="form-control tagin" data-tagin-separator=" " value="red green blue">

Or using option:

const tagin = new Tagin(document.querySelector('.tagin'), {
	separator: ' '

4. Allow Duplicates

Add data-tagin-duplicate to remove duplicates validation.

<input type="text" name="tags" class="form-control tagin" data-tagin-duplicate value="html,html,css,css,js,js">

Or using option:

const tagin = new Tagin(document.querySelector('.tagin'), {
	duplicate: true

5. Transform Tags

Sometimes we need to transform tags. Example tags with toUpperCase(). Using data-tagin-transform attribute:

<input type="text" name="tags" class="form-control tagin" data-tagin-transform="input => input.toUpperCase()" value="HTML,CSS">

Or using option:

const tagin = new Tagin(document.querySelector('.tagin'), {
	transform: 'input => input.toUpperCase()'

6. Force add on enter

Add data-tagin-enter to force adding tag when enter key is pressed.

<input type="text" name="tags" class="form-control tagin" data-tagin-enter value="red,green,blue" data-placeholder="Add a color... (then press comma or enter)">

Or using option:

const tagin = new Tagin(document.querySelector('.tagin'), {
	enter: true



  • 1

    Using tagin class on multiple inputs in same form

    Hi, I have a simple form as shown below where I am using your tagin module on the Pattern and Choices field. If I use the tagin class on a single field everything works fine, however, when I use the the tagin class on both input field, the Pattern field tags correctly but the Choices field disappears. Would be grateful if you can help me out. I have also attached the code below:


    <form action="/intent_add_action" method="POST">
    		<label for="tag">Tag</label>
    		<input type="text" class="form-control" name="tag" id="tag">
    		<label for="pattern">Pattern</label>
    		<input type="text" class="form-control tagin" name="pattern" id="pattern">
    		<label for="responses">Responses</label>
    		<input type="text" class="form-control" name="responses" id="responses" onkeyup="update_editor()">
    		<label for="choices">Choices</label>
    		<input type="text" class="form-control tagin" name="choices" id="choices">
    		<label for="cntx-set">Context Set</label>
    		<input type="text" class="form-control" name="cntx-set" id="cntx-set">
    		<label for="cntx-fltr">Context Filter</label>
    		<input type="text" class="form-control" name="cntx-fltr" id="cntx-fltr">
    	<input class="btn btn-primary btn-lg btn-sm" type="submit" value="Save Intent">


    const tagin = new Tagin(document.querySelector('.tagin'),
    			  separator: ';',
    			  duplicate: false,
    			  enter: false,
    			  transform: 'input => input',
    			  placeholder: ''

    Output: Screenshot (116)_LI

  • 2

    Get multiple values as an array

    I have a problem, I'm trying to get an array with all the tags from the input text as values.

    When i insert some values in the input i get this "123,2131,12" but i need to get something like this ["123","2131","12"], any solution?

  • 3

    Cannot install tagin.min.js from CDN

    Hello, and first off thank you for the excellent little library here!

    I've got a purely static site with no build, and am using Tagin straight from the CDN. It appears that I am able to use tagin.js just fine, but when I instead switch to the minified artifact, Tagin is no longer defined:

    <!doctype html>
    <html lang="en">
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="[email protected]/dist/css/bootstrap.min.css" integrity="sha256-YvdLHPgkqJ8DVUxjjnGVlMMJtNimJ6dYkowFFvp4kKs=" crossorigin="anonymous">
        <link rel="stylesheet" href="[email protected]/dist/tagin.min.css">
        <title>Hello, world!</title>
        <h1>Hello, world!</h1>
          <input type="text" name="tags" class="form-control tagin" value="red,green,blue">
        <script src="[email protected]/dist/js/bootstrap.min.js" integrity="sha256-cMPWkL3FzjuaFSfEYESYmjF25hCIL6mfRSPnW8OVvM4=" crossorigin="anonymous"></script>
        <!-- [WORKING] -->
        <!-- If I import 'tagin.js', this page loads just fine and the tags are displayed -->
        <script src="[email protected]/dist/tagin.js"></script>
        <!-- [NOT WORKING] -->
        <!-- If I instead import `tagin.min.js`, then instead I'll see in the console -->
        <!-- "Uncaught ReferenceError: Tagin is not defined" and no tags are rendered -->
        <script src="[email protected]/dist/tagin.min.js"></script>
          document.querySelectorAll('.tagin').forEach((el) => {
            if (el instanceof HTMLInputElement) {
              const tagin = new Tagin(el)

    I'm not sure if this is just my lack of JS know-how showing or an issue w/ the minified JS, but I'd love any help figuring out how to make use of the minified library!

  • 4

    Allow for exporting tagin as a module


    Add export default to the tagin function:

    export default function tagin(el, option = {}) {

    Import the script as a module:

    <script src="tagin.js" type="module"></script>

    Then it is possible to import tagin inside a script:

    import tagin from "tagin.js";


    This removes the current way of inline importing/using tagin inside HTML:


    Inline JS is generally considered bad practice.


    Easier to import a required function into an existing script file, if there will useful functions in the future.


    Internet Explorer does not support import. (Is that really a con though?)

  • 5

    Dynamically rendered tagin-tag can't get value

    Hi, thank you for this great work, it all worked fine and smooth. But I was trying to dynamically create tagin-tag with js, afterward, I want to retrieve the value out of the input element, but the value is null. But once I manually add some tags In the input field, I can get the input value afterward. Is there any suggestion or ways I can look up to?

    dynacmically render.js

    tagArr.forEach((el) => { const tagEl = document.createElement("span"); tagEl.setAttribute("class", "tagin-tag"); tagEl.innerHTML =${el}; document.querySelector(".tagin-wrapper").appendChild(tagEl); });

    getting value out of it, but it show null.

    const tag = document.querySelector("#tag").value;


  • 6

    Add module export for using tagin via import

    Unfortunately I couldn't get gulp to compile on my system so I didn't update the version in dist.

    But with this small change, I could easily

    import * as tagin from "tagin/js/tagin";
  • 7

    Refactor Tagin as a class

    Allows to easily import the module and use functions such as .addTag() and .getTags() outside the class itself. Also implements #10.

    This eliminates the ugly ways of adding and getting tags:

    // Getting tags:
    // Old way
    // New way
    tagin = new Tagin(document.querySelector(".tagin"));
    // Adding Tags:
    // Old way
    const target = document.querySelector('.tagin');
    target.value = 'red,green,blue';
    target.dispatchEvent(new Event('change'));
    // New way
    tagin = new Tagin(document.querySelector(".tagin"));
    tagin.addTag(False, 'red,green,blue');

    I updated the to reflect the changes.

  • 8

    Add recommendations

    Hi there,

    this isn't really an issue, rather a feature request. It would be very cool if Tagin would support recommendations or something similar like Datalists for Input fields

  • 9

    Value always null

    I have a Laravel Livewire input

    <div class="col-sm-9">
          <input wire:model="school_official_telephone_number" value="{{ $school_official_telephone_number }}" class="form-control tagin" type="text" data-placeholder="Add...">
          @error('school_official_telephone_number') <span class="text-danger f-12 mt-1">{{ $message }}</span> @enderror

    But when I click submit, the value was not recognized.


    //results to `null`


    Any help is much appreciated.

  • 10

    Input field duplicated on dynamic field


    I have run into an issue where my tag field keeps getting duplicated on a dynamic input field.

    This is what happens:


    I am showing the input field on a modal whos content gets automatically populated depending on which element a user clicks on.

    Here is the html for the modal, ignore the curly braces that's the Jinja template tags.

    <ul class="list-group">
        <li class="list-group-item list-group-item-primary" data-qid="{{q['_id']}}"
          data-toggle="modal" data-target="#questionModal" data-question="{{q['question']}}"
          data-explanation="{{q['explanation']}}" data-answer="{{q['answer']}}"
          data-tags="{{q['tags']|join(', ')}}" data-principals="{{q['principals']}}"><b>{{ q['question'] }}</b></li>
        <li class="list-group-item border-top-0 border-bottom-0"><b>Explanation: </b><p>{{ q['explanation'] }}</p></l>

    I update the fields on the modal with an on click from that list item.


    And here is a snippet of the modal

     <div class="form-group col-12">
    <label class="control-label" for="question">Question</label>
    <input type="text" id="question" name="question" value="" class="form-control" style="width:100%" required="" aria-required="true">
    <label class="control-label" for="explanation">Explanation</label>
    <textarea type="text" id="explanation" name="explanation" class="form-control" required="" aria-required="true"></textarea>
    <label class="control-label" for="answer">Answer</label>
    <textarea type="text" id="answer" name="answer" class="form-control" required="" aria-required="true"></textarea>
    <label class="control-label" for="tags">Tags</label>
    <input type="text" id="tags" name="tags" value="" class="form-control tagin">
    <input type="hidden" name="qid" id="qid" value="">
    <input type="hidden" name="action" id="action" value="update">

    If I use the method shown in the example to update the tags field it works, but the old values stay there where I click on another list item (the rest of my fields update fine). I have been able to get it to update on every item, but the input field is then duplicated as shown in the screenshot.

    Any ideas on how I can address this issue?