jQuery Tagit – A jQuery tagging plugin

jQuery Tagit Preview
It depends on jQuery 1.4.2. and jQuery.ui 1.8 The Jquery Tagit Plugintransforms an html unordered list into a unique tagging plugin.Why unique? Because jQuery Tagit uses jQuery UI’s auto-complete plugin to supply suggestions to users as they type and has some awesome features.

Features

  • Convenient way for users to enter a list of items
  • Fully integrated with jQuery ui auto complete
  • Automatically adds current input as tag if input loses focus
  • Easy to use public methods
  • Easy to theme (single css file)
  • Customizable accept keys
  • Backspace on empty input deletes previous tag
  • Ability to provide initial tags on creation though options
  • Ability to provide initial tags on creation via list items
  • Option to toggle usage of a hidden select so the tags can be sent using a normal form!
  • Ability to sort tags via drag and drop!
  • Optional Themeroller Compatibility

Demo

Instead of a whole pile of blabing how about you just check out the demo.

Download from GitHub

Tags: , , , ,

Matthew Hailwood is a Freelance web developer. He specializes in back-end development Specifically PHP5, SQL, and Code Igniter. He is no designer but he has a flair for user experience development using Jquery.

93 Comments Leave yours

  1. Ed #

    Thank you for putting this together. However, I’m a little confused why clicking the Get Tags buttons doesn’t show the tag values in FF 3.6 and Chrome for Mac. Values that are pushed into the array aren’t being alerted.

    Thanks.

  2. Ed #

    To clarify, the issue is with adding tags from the predefined list via autocomplete. There also seems to be a lot of issues with tags being popped and pushed. I’m looking to see if I can debug your code.

    • Ah thank you for noticing this.

      I will work on this issue.

      It is caused because, due to the input having a blur hander(so you can add a tag on focus lost) when you click on an option from the autocomplete you get two tags added, whatever was in the input at the time (eg act) and the option you clicked on (eg action) to bypass this I was removing the last tag from the array in my autocomplete select handler however there seems to be a bug!

  3. Ed #

    Thanks for the reply, Matt. Is this bug related to removing a tag by clicking the “x”? It appears to me that the array is popping the last item regardless of what tag is removed. I think the _popTag function needs a value so that this.tagsArray.pop() should be be this.tagsArray.pop(value)

    • You are correct, something is causing a click event on the little x :/

      >Changing if ($(e.target.tagname == ‘A’) { to if ($(e.target).hasClass(‘tagit-close’)) { fixed it.

      I have uploaded the changes and added you to the credits (check the tagit.js comments at the top).

      Hmm, actually that just stopped the click handler for the x working, I need to work out what is causing it to click…

  4. Ed #

    Thanks, I saw that. Pushing items from the list works great now. The click handler was actually working fine before and I believe it’s the anchor tag that was getting the click. The problem was that no matter what tag was removed, the last tag in the list was always being popped. You need to identify the indexOf the tag in the array and then slice() it instead of pop()

    • wow your right, Your hitting all the bugs I have missed haha. Cheers, Will work on that now.

    • Right, Now all should be good to go, basically you fixed two bugs,

      1) adding an item from the autocomplete was not adding to the array

      2) clicking an ‘x’ would always remove the last item :)

  5. Ed #

    After your _popTag function I added a _sliceTag function:
    _sliceTag: function(pos) {
    console.log(‘slicing: ‘+this.tagsArray[pos]);
    return this.tagsArray.slice(pos);
    }
    ,

    And in the click handler I replaced the self._popTag with:
    var pos = $(e.target).parent().index();
    $(e.target).parent().remove();
    self._sliceTag(pos);

    But the live click event is causing issues :/

  6. Ed #

    Well, hey, if I identified a couple of bugs to make the script work I’m glad I could assist. Your plugin looked very good to me and I was hoping to use it so with everything working I’m excited to try it out.

    • awesome,

      I am planning on adding an option to add a hidden html select.

      basically this means that right under the ul there would be a hidden <select multiple name=”{name attr from ul}”></select>

      Every option in the select will be selected, options will be added and removed dynamically.

      This means that the plugin can be used with a form without having to add a submit handler.

      What do you think?
      Any other improvements you can think of?

      • Ed #

        I think that would be awesome since the values in the select element would all be submitted as a comma delimited array. I’m going to bookmark this post and I’ll be sure to check out the changes. I’ll be happy to test it out for you too :)

        • Guess what,

          Feature added,

          Dang i’m quick ;) Enjoy.

          • Ed #

            Nice! And you are quick ;)

          • Ed #

            I made one last modification to the script. I added an option to give the select element a name. It’ll make reading the values easier when the form is posted.

          • oh, (although I have not properly tested it the script should be getting the name from the name attribute applied to the ul.

            Care the inform me if this is not the case?

          • Ed #

            Hmmmm, maybe I’m missing something but I don’t see how it would be getting the name from the UL. You’re creating the select element with And when I inspect everything with Firebug I don’t see a name attribute on the UL or the select

            By making the select name an option to the plugin I can name it anything I want particularly with regards to how I follow a naming convention

          • hmm, Ill have a look, it should be working that you can make the ul using something like <ul name=”selectName”></ul> and then the select will look like <select name=”selectName”></select>


            Edit:
            And of course you were right ;)

            I thought I added the feature in but I didn’t its in there now.

          • Ed #

            Brilliant! I’ve updated my script

  7. Ed #

    LOL! I like what your method expanding on the _popTag function (one less function to mess around with). An dit looks like the live click event delegation just wasn’t working right. Good too see the classname works for identifying the element.

    Awesome, Job, Matt! Cheers to you :)

  8. There’s a bug with the tag_input variable. You forgot to use var, so a lot of events are firing on the last element to had Tagit applied to it. Once var is added, you have to remove the “this” from “this.tag_input” later on. tag_input is in a closure, so it will continue working.

    Thanks for making this plugin. I needed something like this earlier today, so the release timing was perfect!

    • Wait, it looks like I’m using an older version. The one linked above doesn’t seem to have this issue. Have the download links all been updated?

      Also, having now used the plugin for a bit, it seems that it is fairly simply to replace the UL/LI tags with SPAN tags, which makes it ease

      • Hi Jeff,

        All download links are updated at the same time I update the demo page.

        Please let me know if you are still having problems.

        Also you are correct, Due to the structure of the plugin you could theoretically replace the <ul>/<li>’s with any other element. it just made sense to me to have them as a <ul>.

        Any reason you suggest span tags?

        • The main reason is that span tags can be (more easily) put inline. In my case, I’m using it to tag RSS-items and I have one instance in the footer of each item along with other things. Using spans means that I don’t have to deal with floats, inline-blocks, or anything else to put it inline.

          That said, if you don’t want to do it it’s OK with me. I already made the edits to use spans.

          Thanks for writing this library! It saved me a ton of time creating this functionality.

  9. There’s a small bug in the _popTag function: the first $.inArray() should use “this.tagsArray” and not “this.tagArray” (you forgot an “s”).
    Also, console.log(‘select’); in the _popSelect function is not working in IE.

    Anyway, thanks for the great job! :-)

  10. Hi there!

    Awesome job you did with this plugin! Altough I’m having a problem here, each time I pick an autocomplete option from the dropdown, pressing any key, the tag I chose overwrites the previous one, no matter what.

    If I just click on the option without using my keyboard, it works as intended.

    Do you have any idea what could be causing this behaviour?

    Thanks in advance! And keep up the good work!

  11. Ok, I’ve managed to fix this:

    The problem is in the line 102, apparently when you select an item from the dropdown it first calls self._removeTag() and then self._addTag(), which causes unintentionally to remove the last item you previously selected.

    Removing that removeTag call fixed the problem for me.

    Thanks again!

  12. Great plugin, but I have a question regarding the adding of tags from the predefined list. When you type something and then select a value from the auto-complete list by clicking it, all is fine. However, when you try to add it by hitting TAB on the item in the list, your previous tag will be overwritten. (if the tag you tried to add was already added, the previous tag will even get removed).

    • I have confirmed this is a bug, I will update this comment when I have fixed it (should be in the next few hours) Thanks for the report.

  13. Hi There.

    You may want to fix the download url as it points to ver 1.3 (which isnt there) instead of 1.4.

    Thanks for this great plugin
    - Niro

  14. Hi,

    Thanks for building this. It’s super small and easy to use. I did notice the bug where using the keyboard to select an item from the autocomplete deletes the last tag. Based on the comments it looked like you were going to fix, but I was still seeing the problem.

    I was able to fix this by adding an if (event.keyCode > 0) before the self._removeTag() in the autocomplete ‘select’ handler. Basically, if the user clicks, then the event keyCode will be 0, otherwise they used the keyboard to select the item.

    • Ah perfect!

      I was actually struggling to find a fix for this!

      Will test it out soon and accredit the bug fix to you!

      • Sam #

        That didn’t work for me. Please fix this issue ASAP.

        Thanks for this wonderful pulgin.

  15. Sam #

    How can I force the user to only choose one of the predefined values in availableTags?

    • Hi Sam,
      The plugin was not actually written with this as the intent as the availableTags could be anything from a url to a json object. If you wish you could modify the plugin so in _addTag it does a check to see if the value is in avaliableTags, if not then just call return false;

      But remember this will break it if you use autocomplete.

  16. Hi
    First of all, thank you for building a great plugin Matthew
    I have a suggestion regarding resetting the plugin when a user is finished (not destroying). Something simple like:

    reset: function () {
    this.element.find(“.tagit-choice”).remove();
    this.tagsArray = [];
    }
    I use the plugin in an environment where I want to reset the textbox and clear the array when a user posts and saves the tags, and everything on the page is loaded with ajax so the user may want to add more tags on something else without page reload (and init of the plugin). This scenario may also be applied in an environment where the tagit box is located in a modal popup.

  17. Thank you for this great plugin; I’d like to use it on a web site. What is the licence for this plugin, and where is it specified?

    • Ah Hi Stefan,

      I really should write that down somewhere,

      Basically its a do as you will.

      I.e you can use these for whatever you want, you dont even have to provide a link back if you dont want to!

      I just create these because I think jQuery is awesome!

  18. Hi guys,

    I have released v 1.5 which should fix the autocomplete keyboard selection bug.

    Let me know if there is anything wrong.
    I have not accredited the bug to anyone in particular due to the amount of comments used to fix it.

  19. Hi,

    I have a question.
    I have a DIV consists multiple checkbox. I checked some values, press ‘Insert’ button, the checked values should appear in the tagbox.

    I can do this by SUBMIT the form. The page will be refreshed.
    However, when I try to use .ajax() / .get() / .post() to pass the checkbox values I cannot get it right. So i guess i need a .live() feature?
    But i have no idea how to include the .live() feature for tagit().

    Any good approach instead of refreshing the page?
    Appreciate your advice and help!

  20. Thanks for this great plugin. I’d love to use it for my current project, but I’m really missing an edit functionality. Is there a way to modify existing tags without deleting them?

    Thanks, Alex

  21. Thanks for writing this plugin. Is it possible to put this project on GitHub so it’s easier to submit patches? There are a couple I’ve made (and would like to make).

    • Hi Moses,

      I have actually just startedc using GitHub yesterday so will look into moving these there.

    • Hey Moses,

      I have now moved the plugins to github. Please see the download link above and it will take you to the repo :)

  22. Dear Sir,

    Refer to the query above.
    I’ve tried to manually restructure the list item after i click the INSERT button in order to add in the selected items:
    My concept is, remove all the listed items, then declare it one by one.
    It looks fine but with a problem:
    i cannot turn any new text into tag anymore after i add in the selected items. Any ideas what I’ve missed out?

    Following is the jquery function to insert selected items:

    $(‘#btnClick’).live(‘click’, function(event) {

    var valHidden = [];

    $(‘.tagit-choice’).remove(); // remove all the chosen tag

    $(‘.tagit-new’).remove(); // remove the last tag

    // check for every checkbox

    $(‘#crm_interface_phonebook :checked’).each(function() { valHidden.push($(this).val());

    });

    var areaText = $(‘#mySingleField’).val();

    areaText = areaText + ‘,’+valHidden;

    var exploded = areaText.split(‘,’);

    var sorted_arr = exploded.sort();

    var results = [];

    for (var i = 0; i < exploded.length – 1; i += 1)

    {

    if (sorted_arr[i + 1] != sorted_arr[i])

    {

    results.push(sorted_arr[i]);

    }

    }

    // for each array text

    $.each(results, function(index, value) {

    if (value)

    {

    $('#myTags2').append('’+value+’x‘);

    }

    });

    // append the tagit-new at the back.

    $(‘#myTags2′).append(”);

    // this is the hidden value
    $(‘#mySingleField’).val(areaText);

    });

  23. Tom #

    Great plugin thanks, I set the select:true, and I give my UL a name attribute, but it doesn’t seem to be creating the form select…

  24. Hi Matthew!
    One of the coolest jquery plugins ever!
    Thanks for sharing…

    I have a problem implementing it, actually two..
    1. After selecting tags, and while doing nothing, letters appear as tags randomly, (one letter tags)
    2. Submitting the form, post value of the fields only have one tag, not all tags entered.

    Trying to figure it out took me hours, no luck.
    Hopefully you can pinpoint me in the right direction?

    http://ecompanies.nl/pilot/toevoegen.php

    Thanks again!

  25. Hi Matthew.
    Saw that on your site, the demo, also there are one word tags auto inserted after entering tags, and then waiting..

    On my demo site, I have set select: true, and made it visible with css.. When entering values they appear in wrong select..

    Any help would be highly appreciated!
    thanks

  26. Mm..seems that IE10 doesn’t work with it… not too surprised.. with IE

  27. Hi Matthew, awesome work with this!

    I’ve added a public method:

    addTag: function(tag) {
    this._addTag(tag);
    }

    to add tags clicking on a list of “most used tags”

    $(‘id’).data(‘tagit’).addTag(‘tagname’);

    maybe it can be usefull to someone else.

    thanks for share your work!

  28. I found a little error:

    The 3rd Button has a wrong id: it should be id=”demo3GetTags” (atm its id=”demo13GetTags”).

  29. Hey,

    Firstly, thanks for a great plugin. I had a little idea for an extra feature which may provide useful.

    The ability to limit the amount of tags. I just appended the folowing to the source:


    if (value == "" || this._exists(value) || $('select[name='+this.element.attr('name')+']>option:selected').length > 2)
    return false;

    Im a jquery noob, and not sure of the implications / effects of the addition, but thought this could be built upon by adding an attribute to the element such as “maxTags” and then maybe:


    if (value == "" || this._exists(value) || $('select[name='+this.element.attr('name')+']>option:selected').length > Long.parse(this.element.attr('maxTags')) - 1)
    return false;

    Just a thought, (Code not tested)

    Cheers

  30. Hello. Thanks for this amazing plugin.
    Anyway, it works fine with English but not for Chinese. The problem is when I type Chinese, the input method always eat the key input eg: zhang , eat five keys and at last give “?” return. The single Chinese looks works well too. When I try to input a Chinese word like “??”, the autocomplete feature never fire. I know it should be autocomplete’s issue. But with a small change in tagit, it resolved.
    I added a interval timer to track text change and to manually fire the autocomplete.
    this.input.focus(function(){
    this.key_sim = setInterval(function(){
    if(self.input.val().length > 0 && self.input.data(‘lastValue’) != self.input.val())
    {
    self.input.data(‘lastValue’, self.input.val());
    self.input.autocomplete( “search” ,self.input.val());
    }

    }, 200);

    });

    When blur, I clear the timer.
    this.input.blur(function(e) {
    clearInterval(this.key_sim);

  31. Sel #

    Hello.
    Do you have any sample showing how to prevent to remove a tag?
    What I want to do is to ask the user to confirm the tag’s removal.

    Thanks.

  32. I have not been able to get this or other tag widgets to accept any sort of placeholder text. Any addition of placeholder text tends to break the tagging functionality. Any ideas on how to fix this?

  33. Hello.
    First of all, thanx for great script.
    I’ve found some issues, and, well… Maybe you’ll commit some of my code.

    Adding placeholder and maxlength.

    Near line 5:
    options:{
    placeholder:”Wow, placeholder!”,
    maxlength: 40,
    ———-
    Near line 40:
    this.element.html(”);

    ================================================================================
    Customizing autocomplete.
    Near line 25:
    _create:function(){
    $.ui.autocomplete.prototype._renderItem = function( ul, item) {
    var re = new RegExp(“^” + this.term) ;
    /* autocompleteBold-class – in my case it’s just bold text */
    var t = item.label.replace(re,”+this.term+”);
    if(item.extra){
    /* item.extra could be text or image or anything else */
    t=”+item.extra+’: ‘+t;
    }
    return $( “” )
    .data( “item.autocomplete”, item )
    .append( “” + t + “” )
    .appendTo( ul );
    };

    var self=this;

    ================================================================================
    There’s a bug in _backspace – it doesn’t remove item from hidden select-menu. I guess it’s happens because this._popTag(); on line 192. Your _popTag requires some text, removing it from tagsArray and then calling _popSelect(text) – but if ther is no text – item wouldn’t be removed. I fixed it by replacing this._popTag(); on line 192 with this._popTag(li.html().replace(‘x‘,”"));
    Not the best, but works ok :)

    __
    WBR, Daniel.

  34. It will work in compatibility mode for IE9, but not in regular mode. Anyone have any ideas as to what we can do to make it IE9 compatible?

  35. Mac #

    I’m trying to use this plugin to let people select recipients off a pre-defined list. Is there a way to only let them add tags that already exist, rather than allowing them to create arbitrary new tags?

    Thanks!

  36. I needed a way to re-use the tagit element so I wrote:

    fill: function (tags) {
    this.element.find(".tagit-choice").remove();
    this.tagsArray = [];
    if (tags !== undefined) {
    this.options.initialTags = tags;
    }
    if (this.options.select) {
    this.select.children().remove();
    this.select.change();
    }
    this._initialTags();
    }
    ,

  37. Hello, are there any methods to trigger a tag completion manually?

    • The easiest method for this would be to call blur() on the tagit input. as an example go to the jQuery Tagit demo page and scroll down to demo two. in your javascript console (ctrl + shift + j in chrome, use firebug in firefox) enter $('#demo2 input').val('autotrigger').blur(); and you will see how it works.

  38. Victor #

    Hi Matt,

    There seems to be an issue when event.originalEvent is blank on Line 145 of Tagit.js. In my instance of the plugin, I can navigate up and down the autocomplete list successfully, but I see a Chrome script error : “Uncaught TypeError: Cannot read property ‘originalEvent’ of undefined”
    It references Line 145.

    I am running Chrome 17 in Mac OS X 10.7.3.
    It seems that the code is assuming originalEvent will have something in it, and while I don’t know how the system works, it seems my particular installation doesn’t populate the object and as such throws an error.
    As I said, it doesn’t seem to affect operation because I can use the keyboard keys to select the suggested tag and enter it into the list.

    Let me know if you have an idea on why that happens. For the moment I’ve simply made the conditional statement on Line 145 the following:
    if (ui.item.label !== undefined && /^key/.test(event.originalEvent)) {

    Regards,

    Victor

  39. fre #

    hi,

    is it possibile send the tags to a php script?

    i would store the tgas entered. thank you.

    • It certainly is, What you need to do is capture the tags (see the demo page for how to do this) and then simply submit it to your PHP script (ajax!).

      The other option of course is that this will work perfectly well just in a normal form, so if you are submitting this as a normal form you don’t need to do a thing! these will automatically be received on the other side as if they had just used a normal html select!

  40. Pete #

    Just a suggestion: An option that prevents users from creating their own tags. That is, only tags which shows up in the autocomplete-box should be able to be chosen.

    • That option already exists :) just set allowNewTags to false in the options :)

      • allowNewTags isn’t mentioned in the documentation on this page. Nor is the fact that you can add a tagValue attribute to li elements when defining initial tags, which allows you to display a label that is different to the value stored in the hidden select

  41. Hi, just downloaded the plugin, thanks for writing it! One quick note: my Google search dropped me at the demo http://webspirited.com/tagit/ which has no link to the github repo to download the plugin. Had to do a bit of digging to find it (through this article). Totally worth it, though!

  42. The maxTags option only works for keyboard-selected tags – not if you mouse-click from an auto-complete list.
    I’ve added a simple check to my code to get this to work.

    //setup autocomplete handler
    var os = this.options.select;
    this.options.appendTo = this.element;
    this.options.source = this.options.tagSource;
    this.options.select = function(event, ui) {
    clearTimeout(self.timer);
    if(self.options.maxTags == undefined || (self.options.maxTags !== undefined && self.tagsArray.length < self.options.maxTags)) // CLS-added
    {
    if (ui.item.label === undefined)
    self._addTag(ui.item.value);
    else
    self._addTag(ui.item.label, ui.item.value);
    } // CLS-added
    return false;
    }

  43. Eric #

    Nice but it would be even better if could add spaced tags, for e.g “Double Decker” as 1 tag instead of 2

  44. Peter #

    Hi Matt

    You library seems great and I like the speed of fixes you produces :)

    Your library resembles this one: https://github.com/aehlke/tag-it – is your code just a new branch of their code or something entirely different? Sorry I have not been able to look much into it yet.
    Hoping for an answer.

    Cheers
    Peter

    • It’s actually completely different, coded from scratch,

      I guess it’s just a case of great minds think alike :)

      I originally created this as I needed something in this strain for my work, and thought I would share it :)

  45. jMike #

    How can this jQuery plugin just accept “allowed” values from the availableTags array? By default it accepts any input, even one that is not listed in the array/dropdown. How can you force the plugin to accept only “valid” entries from the array?

    • jMike #

      Ah… just found the option by reading the other posts… you have to set “allowNewTags:false” …

      I suggest to add this option to the docs! :-)

  46. jMike #

    How can i trigger the popup to show immediately? (either through a click on an icon or when the user did not type anything yet? (when the n-th tag is empty)

    • You mean trigger the autocomplete popup?

      I think you would have to reference the autocomplete jQuery object and do something similar to http://bit.ly/KCqBhU.
      This is more a autocomplete thing than something to do with the tagit plugin. :)

  47. Bhuvaneswaran #

    Hi,

    I like your Tag It plugin. i am developing one website. i want to run your plugin it on by AJAX call by JSON.i.e. tags getting from the database instead of static tags.

    Can you help me out of this

  48. KV #

    Is htere a way to autoselect the first time with autocomplete?

    • Yep,

      The options array actually gets passed through to the autocomplete options,

      so when you initialize the plugin simple set autoFocus: true

  49. Nir #

    Hi Matthew,

    Thanks for the tagit plugin. It is awesome.

    I’m using it and it seems to work well on all browsers besides chrome.
    On Chrome I see a checkboxes stacked on the left hand side of the screen. The checkboxes are actually the tags with this html:

    Here is a screenshot: http://awesomescreenshot.com/022jfc430

    Any idea how I can solve it?

    Thanks!
    Nir

    • Hi there,

      I am not sure how Tagit could be the cause of this issue, as Tagit does not use checkboxes at all!

      If you could provide some actual html I could possibly be of more help.

      • Nir #

        Thanks for the quick reply!

        You are correct it is part of my code!

        Have a nice day

        - Nir

  50. Sagar #

    Very good Component for tagging.
    Thank you very much.

    I have removed the trigger keys ‘space’ and i want to create like if user added space then it will converted to the -. Is it possible?

    Eg: If I am Entering ‘tagit jQuery’ then it should be converted like ‘tagit-jQuery’.
    Inshort i need to replace ‘space’ with ‘-’ when tag is created.

6 Trackbacks

Leave a Reply





That's Me, I'm a web developer who's main focus is actually Back-end, Specifically PHP development. But every now and then I come up with something awesome for the front-end and this is where I share it!

More updates on Twitter