How to filter select list options

Here’s a jQuery extension method to filter the elements of a select list (option tags). It binds to a textbox, and as you type in the textbox the select list gets filtered to match what you are typing.

jQuery.fn.filterByText = function(textbox, selectSingleMatch) {
  return this.each(function() {
    var select = this;
    var options = [];
    $(select).find('option').each(function() {
      options.push({value: $(this).val(), text: $(this).text()});
    });
    $(select).data('options', options);
    $(textbox).bind('change keyup', function() {
      var options = $(select).empty().scrollTop(0).data('options');
      var search = $.trim($(this).val());
      var regex = new RegExp(search,'gi');

      $.each(options, function(i) {
        var option = options[i];
        if(option.text.match(regex) !== null) {
          $(select).append(
             $('<option>').text(option.text).val(option.value)
          );
        }
      });
      if (selectSingleMatch === true && 
          $(select).children().length === 1) {
        $(select).children().get(0).selected = true;
      }
    });
  });
};

Parameters:

  • textbox
    This could be a jQuery selector, a jQuery object, or a DOM object.
  • selectSingleMatch
    This is optional, if you set it to true, when the filtered list includes only one item, that item will be automatically selected.

For example:

$(function() {
  $('#select').filterByText($('#textbox'), true);
});  

Live example (or in a new window):

You can play around with it on jsbin: http://jsbin.com/egogeh/edit

What it does:

When you invoke the function on a select object, it finds all child option tags and saves their text and values into an array. This array is saved to the select object itself as a HTML5 custom data attribute, called data-options. Then, when a change or keyup event fires on the associated textbox, the select list is emptied, and for any entries in the array that match the search text a new option element is created.

Edit 2012-10-15: Added ScrollTop(0) to improve the way it works with long lists, thanks to a comment by xarel below.

This entry was posted in Technology and tagged . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

53 Comments

  1. Raam
    Posted 2011/08/25 at 2:14 pm | Permalink

    Hi, Thats a good one…. Thank you.. I have a question if you could help me with it will be great..

    I am creating a small troubleshooting guide which is created in Jquery and HTML. When user selects a step this is designed to give next step to try and from there next one in a flow chart style.

    I want to add a textbox to which the selections will auto populate. After troubleshooting they should be able to copy all selected items from the text box. Can anyone help me with a code which will auto populate all user selected items from the flow into a text box.

    Please find the code I used for the troubleshooting guide. Any help will highly appreciated.. Thanks in advance..

    $(‘document’).ready(function(){
    var count = 0;
    $(‘#questions’).hide();
    $(‘#answers’).hide();
    $(‘#questions tr:nth-child(2)’).attr(‘id’,’currow’);
    var q1 = $(‘#currow td:nth-child(2)’).html();
    var q3 = ” + q1 + ” ;
    var a1 = $(‘#currow td:nth-child(3)’).html();
    var r1 = q3 + a1 +”;
    $(‘#showquestion’).html(r1);

    $(‘li’).live(‘click’,function(){
    $(this).addClass(‘selected’).siblings().removeClass(‘selected’);
    var target = $(this).attr(‘id’);
    var parid = $(this).parent().parent().attr(‘id’);
    var parnum = parseInt(parid.slice(1,3));
    count = count + 1;
    var ps = $(‘#showquestion div’).length;
    $(‘#showquestion div’).each(function() {
    var divid = $(this).attr(‘id’);
    var divnum = parseInt(divid.slice(1,3));
    if(divnum > parnum)
    $(this).remove()
    })
    $(‘td’ ).each(function(){
    var qnum = $(this).text();
    if(qnum == target) {
    var q = $(this).next(‘td’).html();
    var q2 = ” + q + ”;
    var a = $(this).next(‘td’).next(‘td’).html();
    var qs = $(‘#showquestion’).html();
    var r = qs + q2 + a +”;
    $(‘#showquestion’).html(r);
    window.scrollBy(0,400);
    }
    })
    })
    })

    Support System

    No
    Question/Heading
    Answers

    1
    Question 1

    Option 1
    Option 2
    Option 3

    2
    Level 2 – from question 1 Option 1

    Option 1
    Option 2

    3
    Level 2 – from question 1 – no

    Option 1
    Option 2
    Option 3
    Option 4

    4
    Level 3 – from level 2 option 1

    Option 1
    Option 2
    Option 3
    Option 4

    Text Field:

  2. PR
    Posted 2011/11/09 at 4:28 pm | Permalink

    This is awesome! Just the solution I had been looking for. Came across other filter functions but it wouldn’t work on my Struts2 select list. Thank you for posting an optimal solution.

  3. Erie88
    Posted 2012/03/12 at 3:43 pm | Permalink

    Thank you so much, I have been looking for this. It works great and simple.

  4. Posted 2012/07/05 at 7:31 am | Permalink

    Algunas veces tengo que hacer doble click para que me seleccion el list box, alguna sugerencia???

  5. Umuayo
    Posted 2012/07/10 at 5:49 pm | Permalink

    Thanks, this is what I actually needed, but I have many Select multiple box options in my page which I would like to use this script for filtering. Already it is working in one select Option. How can I make this (global) be used by all the select multiple options instead of creating many scripts, I need to have one script be used by all other Select multiple options for filtering.
    Auto Filter

    =======================
    Auto Filter

    ============================
    Auto Filter

    =================================
    Auto Filter

  6. Posted 2012/07/10 at 6:06 pm | Permalink

    You can use it on many select multiple boxes. You just need to bind each one, for example:

    $('#select').filterByText($('#textbox'), true);
    $('#select2').filterByText($('#textbox2'), true);

  7. Posted 2012/09/17 at 12:07 am | Permalink

    Hi.
    Great script, thank you for posting it. The site I’m working on has literally thousands of products and categories, so this is something of a life-saver where auto-complete isn’t possible.
    There was one small niggle in our case – so many options in the select element that after the first keypress there was a significant pause while the script found every option with that letter in.
    At line 9 I added:
    $(select).data('options', options);
    $(textbox).bind('change keyup', function() { // this is line 9
    if (textbox.value.length > 1) {

    And then of course added another } to what then became line 27.

    That makes the filter only kick in once there are at least two characters in the text field.
    Thanks again :)

  8. Posted 2012/09/17 at 12:07 am | Permalink

    Hah, line 9 is actually the line one line BELOW that one.

  9. Posted 2012/09/17 at 4:10 pm | Permalink

    Great Tom, thanks for contributing your modification :)

  10. Mathis Neumann
    Posted 2012/09/19 at 1:17 am | Permalink

    Hi there,
    I am currently missing one feature, which is the saving of already selected options.

    Let me explain that: I have a very large list of possible selections and want a simple way to filter the list, select the one option I want, reset the filter and select the next one (using the control key). What it does for now is that it let’s me filter the options, select one or more which are currently in that selection, but if I reset the filter or write a bit more in the filter, the selection I made previously gets deleted.

    Is there a way to fix that?

    Thanks,
    Mathis

  11. Tom
    Posted 2012/09/19 at 2:50 am | Permalink

    Mathis… You need to use jquery to create a copy of your select element, then remove all the options from the original. Then create a button that adds options back in from the copy and select them. Obviously the filter would be attached to the copy, not the empty original.

  12. xarel
    Posted 2012/10/14 at 8:45 pm | Permalink

    Hi, this works great, thank you very much!
    One question: My option tags have a class for different formatting, such as:
    value1

    When filtering, the class gets lost. Is there an easy way to preserve it?
    Yes, I am a complete newbie to jquery…

  13. Posted 2012/10/15 at 2:19 pm | Permalink

    You can make the following two modifications to preserve the class(es) on the option tags:

    line 7: options.push({value: $(this).val(), text: $(this).text(), className: $(this).attr('class')});
    line 19: $('<option>').text(option.text).val(option.value).addClass(option.className)

    See it in action here: http://jsbin.com/egogeh/216/edit

  14. xarel
    Posted 2012/10/15 at 8:21 pm | Permalink

    Works perfectly, thank you!!
    Ok, one more question: I have a large list, if I start typing while I am at end of the list, and the filter result contains just a few entries, the option list window is stuck at the lower end and won’t show any entries. I have to move the scrollbar a bit to make the items appear.
    I tried $(select).scrollTop() at various positions, but could not see any effect. Is scrollTop() the correct method? And where would be a good place to execute it?
    Thank you very much for your help!

  15. Posted 2012/10/15 at 10:42 pm | Permalink

    You can add .scrollTop(0) to line 11 to get the select list to scroll to the top:

    var options = $(select).empty().scrollTop(0).data('options');

    Live: http://jsbin.com/egogeh/218/edit

    And thanks for letting me know about this – I had never tried it with a long list like that! :)

  16. xarel
    Posted 2012/10/17 at 10:55 pm | Permalink

    Dear Lessan,

    this works excellent, too. Thank you very, very much for your help, you saved me hours of trial and error. Also, thanks for that jsbin link, nice way to play and learn with jquery.
    Best regards,
    x

  17. Posted 2012/10/18 at 9:18 am | Permalink

    Thanks for help ,
    I want to some more help .I want to give search option in under select box.After click on select box user is able to see all field name in option as well as can see search input box in under select box and after enter any keyword shorting is perform .
    This all work shall be happen with ajax .

  18. Posted 2012/10/18 at 9:19 am | Permalink

    Thanks for help ,
    I want to some more help .I want to give search option in under select box.After click on select box user is able to see all field name in option as well as can see search input box in under select box and after enter any keyword shorting is perform .
    This all work shall be happen with ajax .

  19. PRM
    Posted 2012/12/20 at 12:48 am | Permalink

    Sweet! but here is my situation i have optgroup for each option and I want to show optgroup along with matching option every time it filter. Please help me how can i do it?

  20. JPB
    Posted 2013/01/04 at 11:07 am | Permalink

    Works great for initial, HTML-embedded selectlists.

    I populate my selectlist using AJAX in a dynamic way. The filter works after invoking on the initial HTML-embedded selectlist. How can I solve this ?

  21. Posted 2013/01/06 at 8:39 pm | Permalink

    You will need to figure out how to invoke a command after your selectlist has been populated using AJAX. There, simply place the call to initialize the function:

       
    $('#select').filterByText($('#textbox'), true); 
    
  22. JPB
    Posted 2013/01/11 at 3:07 pm | Permalink

    1) The page shows a selectlist in the HTML. The filter works perfect!
    2) When I re-populatie this selectlist with new options, using AJAX, then the filter re-populates the selectlist with the options that were initially present. My AJAX-filled selectlist is gone !

  23. JPB
    Posted 2013/01/11 at 3:14 pm | Permalink

    1) The page shows a selectlist in the HTML. The filter works perfect!
    2) When I re-populatie this selectlist with new options, using AJAX, then the filter re-populates the selectlist with the options that were initially present. My AJAX-filled selectlist is gone !

    I found it: re-invoke the filterbyText() function directly after AJAX filled the options ! An initial invocation is not enough. Thank you, it’s working fine now!

  24. Andrew B
    Posted 2013/01/28 at 1:13 pm | Permalink

    Hello

    Great plugin, I use it a lot. The only trouble was that the selects optgroups got removed by the plugin. I have rewritten it to preserve the optgroups (If it has any), and also added a minimum text length parameter to the functions options. I also removed the change event on the textbox because it was causing the filtering to fire twice.

    I’m only a PHP developer and not a JavaScript Dev so I probably rewritten some of it wrong.

    jQuery.fn.filterByText = function(textbox, selectSingleMatch, minimumTextValue) 
    {
      return this.each(function() 
      {
        var select = this;
        var optionsAndOptGroups = [];
        
        if(typeof selectSingleMatch === "undefined")  {   selectSingleMatch = false;   }
        if(typeof minimumTextValue === "undefined")  {   minimumTextValue = 0;  }
    
        //Find all options and option groups
        $(select).children('option, optgroup').each(function()
        {
          //Option group? Need to build options 
          if($(this).is("optgroup"))
          {
            var options = [];
            $(this).children('option').each(function() 
            {
              options.push({tagName: $(this).get(0).tagName, value: $(this).val(), text: $(this).text()});
            });   
            optionsAndOptGroups.push({tagName: $(this).get(0).tagName, label: $(this).attr('label'), options: options});
          }
          //Just an option with no group?
          else
          {
            optionsAndOptGroups.push({tagName: $(this).get(0).tagName, value: $(this).val(), text: $(this).text()});
          }
        });
    
        $(select).data('optionsAndOptGroups', optionsAndOptGroups);
    
        $(textbox).bind('keyup', function(e) 
        {
          //If del / backspace is pressed then we still want to filter the select to shown previously hidden elements
          if(textbox.val().length > minimumTextValue || e.which === 46 || e.which === 8)
          {
            var optionsAndOptGroups = $(select).empty().data('optionsAndOptGroups');
            var search = $.trim($(this).val());
            var regex = new RegExp(search,'gi');
    
            $.each(optionsAndOptGroups, function(i)
            {
              var jQueryObject = $('<' + optionsAndOptGroups[i].tagName + '>');
              if(jQueryObject.is('option'))
              {
                if(optionsAndOptGroups[i].text.match(regex) !== null) 
                {
                  $(select).append(jQueryObject.text(optionsAndOptGroups[i].text).val(optionsAndOptGroups[i].value));
                }   
                $(select).append(jQueryObject);
              }
              else if(jQueryObject.is('optgroup'))
              {
                var optionsAdded = false;
                jQueryObject.attr('label', optionsAndOptGroups[i].label);
                $.each(optionsAndOptGroups[i].options, function(index)
                {
                  if(optionsAndOptGroups[i].options[index].text.match(regex) !== null) 
                  {
                    optionsAdded = true;
                    $(jQueryObject).append($('<option>').text(optionsAndOptGroups[i].options[index].text).val(optionsAndOptGroups[i].options[index].value));
                  }
                });
                if(optionsAdded === true)  {   $(select).append(jQueryObject); }
              }
            });    
          }
        });
        if (selectSingleMatch === true && $(select).children().length === 1) 
        {
          $(select).children().get(0).selected = true;
        } 
      });
    };
    
  25. Andrew B
    Posted 2013/01/28 at 1:17 pm | Permalink

    Ah it stripped a line of code because of the html tag…


    //Replace
    var jQueryObject = $('");
    //With
    var jQueryObject = $('<' + optionsAndOptGroups[i].tagName + '>');

  26. Andrew B
    Posted 2013/01/28 at 1:19 pm | Permalink


    //Replace
    $(jQueryObject).append($('').text(optionsAndOptGroups[i].options[index].text).val(optionsAndOptGroups[i].options[index].value));
    //With
    $(jQueryObject).append($('<option>').text(optionsAndOptGroups[i].options[index].text).val(optionsAndOptGroups[i].options[index].value));

    Sorry for flooding your comments section i couldn't edit my original post

  27. Posted 2013/02/04 at 9:02 pm | Permalink

    No worries about the comments. Thank you for the contribution!

    I updated your comment with the edits you mentioned. I also used [js][/js] instead of <code> for the code formatting.

  28. Joe H.
    Posted 2013/02/08 at 3:40 am | Permalink

    This is exactly what I need …. but one small problem

    After I filter I want to use the selected item in an Ajax call to do a database insert. My problem is that I cannot seem to get the selected item. I run this function on a button press:

    function addSkill() {
    var selectVal = $(‘#ab_chooser :selected’).val();
    var selectText = $(‘#ab_chooser :selected’).text();
    alert(selectVal+” “+selectText);
    }

    This only causes an alert box is ‘undefined’ to show up. Any help?

    Thanks!

  29. Joe H.
    Posted 2013/02/08 at 3:42 am | Permalink

    Nevermind… I figured out my problem. I had forgot that I had renamed my select box to “ab_chooser1″

  30. David O.
    Posted 2013/02/08 at 7:47 am | Permalink

    Can I get some help please. I’m trying to create multiple select filters.
    There are 3 drop down boxes for Country, State and City.
    First I select “Country”. It shows the States.
    Then I select the “State” and it shows me the cities.

    How can I do this? thank you.

  31. Jenn
    Posted 2013/03/21 at 11:19 pm | Permalink

    This is awesome! I had it up in minutes! Thanks a million!!!

  32. Sam I Am
    Posted 2013/04/11 at 12:09 am | Permalink

    Very nice script that saved a lot of time. I noticed one issue.
    1. If the value in the select has a ‘(‘ or ‘)’ char (and likely other special chars), the functionality breaks.

    It would also be nice if the regexp ignored whitespace. In my case the values have linebreaks and often more than a single whitespace. I would like to have it ignore whitespace in matching.
    Thanks

  33. Sam I Am
    Posted 2013/04/11 at 4:41 pm | Permalink

    To correct the special chars update your script from:

    //var search = $.trim($(this).val());

    To:

    var search = $.trim($(this).val().replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"));

  34. Sam I Am
    Posted 2013/04/15 at 10:50 pm | Permalink

    Here is the cleaned up version that handles special chars and totally ignores whitespace. Yoyu can easily modify the code to have flags besides selectSingleMatch that control this new functionality.

    var search = $.trim($(this).val());
    search = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
    //search = search.replace(/\s* /g, '\\s*'); //ignore extra spaces or linebreaks
    search = search.replace(/\s*/g, '\\s*'); //totally ignore whitespace
    
  35. Posted 2013/04/26 at 10:40 am | Permalink

    So happy with this script and made a little modification to the call of it to make it work on every select box in a CMS of ours.

    	$(function() {
    		$('select').each( function(index) {
    			$(this).after('Filter dropdown: ');
    			$(this).filterByText($('#'+$(this).attr('id')+'search'), true);
    		});
    	});
    

    Loops through all select boxes and so long as they have an id with create a unique filter box for them.

    Thanks again!

  36. Posted 2013/04/26 at 10:42 am | Permalink

    Hmm, used the code tag wrong. Please delete both these posts admin ;)

  37. Posted 2013/04/29 at 9:55 am | Permalink

    I updated your comment to use [js] instead of <code>.

  38. Sam I Am
    Posted 2013/05/01 at 12:11 am | Permalink
    var options

    is defined twice. Very confusing code.

  39. Geo316
    Posted 2013/06/13 at 10:57 pm | Permalink

    I was wondering – is it possible to only filter options that are NOT defined as selected? It is important for me to not filter options already selected.

  40. Srinivas
    Posted 2013/07/01 at 8:44 pm | Permalink

    Man, you are a life saver. I have some code but it’s only working in mozilla. This one on the other working with every browser. Many kudos to you.

  41. cheton
    Posted 2013/09/25 at 3:22 am | Permalink

    It’s required to trigger the change event when single match is selected.

    if (selectSingleMatch === true && $(select).children().length === 1) {
    $(select).children().get(0).selected = true;
    $(select).trigger('change');
    }

  42. Andrew Berridge
    Posted 2013/12/05 at 5:08 pm | Permalink

    I use this function a lot to filter selects because its so useful. I’ve rewritten again it to store the actual jQuery objects (Rather than the some of the selects attributes). using this will preserve any custom attributes that you may have on the options / optiongroups.


    jQuery.fn.filterByText = function(textbox, selectSingleMatch, minimumTextValue)
    {
    return this.each(function()
    {
    var select = this;
    var optionsAndOptGroups = [];

    if(typeof selectSingleMatch === "undefined") { selectSingleMatch = false; }
    if(typeof minimumTextValue === "undefined") { minimumTextValue = 0; }

    //Find all options and option groups
    $(select).children('option, optgroup').each(function()
    {
    optionsAndOptGroups.push($(this));
    });

    $(select).data('optionsAndOptGroups', optionsAndOptGroups);

    $(textbox).bind('keyup', function(e)
    {
    //If del / backspace is pressed then we still want to filter the select to shown previously hidden elements
    if(textbox.val().length > minimumTextValue || e.which === 46 || e.which === 8)
    {
    var optionsAndOptGroups = $(select).empty().data('optionsAndOptGroups');
    var search = $.trim($(this).val());
    var regex = new RegExp(search,'gi');

    $.each(optionsAndOptGroups, function()
    {
    if($(this).is('option'))
    {
    if($(this).text().match(regex) !== null)
    {
    $(select).append($(this));
    }
    }
    else
    {
    var optionGroupClone = $(this).clone(); //Clone the option instead of using the stored, so we can restore the group to its initial children
    $.each(optionGroupClone.children('option'), function()
    {
    if($(this).text().match(regex) === null)
    {
    $(this).remove();
    }
    });
    if(optionGroupClone.children().length) { $(select).append(optionGroupClone); }
    }
    });
    }
    });
    if (selectSingleMatch === true && $(select).children().length === 1)
    {
    $(select).children().get(0).selected = true;
    }
    });
    };

  43. Sam I Am
    Posted 2013/12/24 at 8:10 pm | Permalink

    Andrew,
    Thanks for that update. It allowed me to remove a hack I had that added this

    if(option.text.match(regex) !== null){//modified to set title
        jQuery(select).append(jQuery('<option>').text(option.text).val(option.value).attr('title', option.value));
    }

    My only other tweak was the addition of:

    var search = jQuery.trim(jQuery(this).val()); //existing
    search = search.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); //NEW  escape special chars
    search = search.replace(/\s* /g, '\\s*'); //NEW ignore extra spaces or linebreaks
  44. Posted 2014/01/10 at 4:17 pm | Permalink

    For multiselect search, with the option to remove elements from one select and add them to another, see here ;)

  45. Sam I Am
    Posted 2014/01/14 at 1:06 am | Permalink

    Note that the code

    $(select)

    is used way too many times and causes a measurable performance degradation in cases where there are many options in the select. The only reason I need filtering is due to the large number of options in my case. This should be cached.
    Change

    var select = this;

    to

    var select = $(this);

    and all the other references of

    $(select)

    to

    select

    I would also suggest the use of jQuery as opposed to $ to avoid conflicts.

  46. Otineb
    Posted 2014/03/13 at 9:58 am | Permalink

    This is amazing! How would I modify this to use a value (such as user id) instead? My use case requires a user select his own name from a group list. I was hoping to cut down on clicks by auto selecting the option by feeding your script the user id value.

    Currently, it only seems to work with an input event. (kind of noob at this sorry!)

  47. ShadowLord
    Posted 2014/05/23 at 4:27 pm | Permalink

    Thanx man!

  48. Conner Smith
    Posted 2014/07/26 at 12:27 am | Permalink

    I made a small update to the code to slightly increase performance if you have a lot of options. Instead of appending each option one at a time, I prepare a list of options and append only once.

        var new_options_html = '';
    
        $.each(options, function(i, option) {
    
          if(option.text.match(regex) !== null) {
    
            new_options_html += '<option value="' + option.value + '">' + option.text + '</option>';
    
          }
    
        });
    
  49. Conner Smith
    Posted 2014/07/26 at 12:31 am | Permalink

    Seems like the last comment got cut off? Trying again!


    var new_options_html = '';

    $.each(options, function(i, option) {

    if(option.text.match(regex) !== null) {

    new_options_html += '' + option.text + '';

    }

    });

  50. Conner Smith
    Posted 2014/07/26 at 12:33 am | Permalink

    Ah, it’s filtering out my tags. So where it shows new_options_html += I’m creating html and using option tags. Such that: (option value=option.value) option.text (/option)

  51. Posted 2014/07/26 at 9:02 am | Permalink

    Thanks Conner. I updated your comment to include the html that was being filtered out. I hope it’s ok now :)

  52. Sam I Am
    Posted 2014/07/30 at 1:12 am | Permalink

    Conner, is there an efficient way to do what you are doing using Andrew Berridge’s suggestion above of using JQuery objects?
    Thanks

  53. Citrix237
    Posted 2014/08/08 at 4:34 pm | Permalink

    Hi Lessan,

    I’m facing an issue with your filter (that I find really really cool) !

    I have a select list with Countries – Towns – Places in towns and when I type the country it filters correctly and when I continue the fist item matching the first letter of the towns disapear. To be clear, this is what I have :

    Cameroon – Douala – Place 1
    Cameroon – Yaounde – Place 2
    Kenya – Nairobi – Place 1
    Kenya – Nyeri – Place 2

    When I type “Cameroon” I have

    Cameroon – Douala – Place 1
    Cameroon – Yaounde – Place 2

    And when I start typing the “-” I only have “Cameroon – Yaounde – Place 2″ and “Cameroon – Douala – Place 1″ dispear.

    I don’t know what’s wrong, may be it’s because it’s the first element in my select box or ??

    Can someone help me to fix this please ? Thanks

2 Trackbacks

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*


+ 5 = ten

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>