Simple tag input for Bootstrap

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

Tagin

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

Demo: https://tagin.netlify.app/

Features

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

Installation

Install tagin with npm:

npm install tagin

Install from cdn:

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

Usage/Examples

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

<head>
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/tagin.min.css">
</head>

Place js before </body> tag:

<body>
    ...
    <script src="https://unpkg.com/[email protected]/dist/tagin.min.js"></script>
</body>
  • 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'
</script>

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
})

Github

https://github.com/erwinheldy/tagin

Comments(10)

  • 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:

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

    Script:

    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">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
    
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha256-YvdLHPgkqJ8DVUxjjnGVlMMJtNimJ6dYkowFFvp4kKs=" crossorigin="anonymous">
        <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/tagin.min.css">
    
        <title>Hello, world!</title>
      </head>
      <body>
        <h1>Hello, world!</h1>
    
        <form>
          <input type="text" name="tags" class="form-control tagin" value="red,green,blue">
        </form>
    
        <script src="https://cdn.jsdelivr.net/npm/[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="https://unpkg.com/[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="https://unpkg.com/[email protected]/dist/tagin.min.js"></script>
        
        <script>
          document.querySelectorAll('.tagin').forEach((el) => {
            if (el instanceof HTMLInputElement) {
              const tagin = new Tagin(el)
            }
          })
        </script>
      </body>
    </html>
    

    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

    Solution:

    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";
    
    tagin(document.querySelector('.tagin'))
    

    Reason:

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

    <script>
        tagin(document.querySelector('.tagin'))
    </script>
    

    Inline JS is generally considered bad practice.

    Pros:

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

    Cons:

    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;

    Thanks!

  • 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
    input.value.split(',');
    
    // New way
    tagin = new Tagin(document.querySelector(".tagin"));
    tagin.getTags();
    
    
    // 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 README.md 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
    </div>
    

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

    image

    dd($this->school_official_telephone_number);
    
    //results to `null`
    

    image

    Any help is much appreciated.

  • 10

    Input field duplicated on dynamic field

    Hello,

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

    This is what happens:

    image

    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.

    $("li[data-target='#questionModal']").on('click',function(){
    	$("#delete_qid").val($(this).data('qid'));
    	$("#qid").val($(this).data('qid'));
    	$("#question").val($(this).data('question'));
    	$("#explanation").val($(this).data('explanation'));
    	$("#answer").val($(this).data('answer'));
    	$("#tags").val($(this).data('tags'));
    	tagin($("#tags")[0]);
    });
    

    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">
     </div>
    

    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?