Chosen: html5 required attribute support?

Created on 4 Mar 2012  ·  80Comments  ·  Source: harvesthq/chosen

When chosen is initialized on a select input, it adds [style="display:none"] to the select tag and creates the various div tags it needs, as follows.

<select name="country" id="country" style="display: none; " class="chzn-done">
    <option selected="selected" value=""></option>
    ...
</select>

This is fine, but we have a problem if I add the html5 'required' attribute to my select tag, which produces the following markup after chosen initializes:

<select name="country" id="country" required="required" style="display: none; " class="chzn-done">
<option selected="selected" value=""></option>
...
</select>

The problem occurs when the user submits the form without selecting a value. To the user, the browser seems to do nothing. In fact, it's displaying an error message to the user to select a value, but because the CSS instructs the browser not to show the select element, the error message also doesn't appear.

This is happening in Chrome, I'm not sure about the behaviour of other browsers.

I haven't dug deep enough to suggest a solution, but this is an issue as we start to include html5 attributes in our forms.

Feature Request

Most helpful comment

+1

Can somebody commit a fix for this? It's pretty old issue and very important functionality nowadays. Thank you.

All 80 comments

I've also just recently noticed this issue.
Required is not supported in all browsers, so I've created a fallback to loop through the elements of a form on submit and verify that there is some value there when "required" is present.
The problem still exists in chrome because the hidden select has no value and is not alerting the user as per the webkit docs:
http://trac.webkit.org/wiki/Styling%20Form%20Controls

"A validation message consists of four div elements with pseudo classes and some nodes for message text. You can customize the appearance by changing the style of these pseudo classes."

I'm thinking the best way to deal with this is to have chosen generate the additional markup to their rendered select with similar classes so that they will be styled by default in the browser, or potentially append pseudo elements to elements that have failed validation by using the appropriate failed conditions in CSS like :invalid.

For now, it looks like your only option is to have a DOM-level fallback like my javascript solution. I can provide it here if that would be helpful but it's really a fallback to chosen, not a way to fix the chosen framework.

What's the status on this issue ? I have the exact same problem with the last version of Firefox ( 14.0.1 )

Since HTML5 attributes are more and more used in websites, this should be adressed a way or the other.

I have the same issue too. I would be curious to know your fallback solution.

Thanks

It looks like there is only 1 major problem, and a secondary problem that would be great to fix.

  • If the form element is invalid (nothing is selected) browsers will kick up a little flag that shows the position of the error, with a message saying to fill this field out. With chosen, in Firefox, that message flag is in the bottom left of the browser window.
  • There is no style defined for invalid form fields. By default in Firefox (it varies between browsers, but they all do something similar) you get a red glow affect around each invalid form field. Chosen select boxes get nothing.

The first item is the more problematic one. Could this be fixed by utilizing a different select element hiding method? Replacing "display:none" on the hidden select element with "position: absolute;visibility: hidden;" gets pretty close - though that'll be more dependent on surrounding CSS...

It doesn't work for Webkit though. It seems the error flag inherits the styles of the select box in webkit (Chrome), so if you set opacity: .5, the flag will also be opacity .5 (as one example). bummer.

One more - Opera works correctly as is, but if I change it to the above position based CSS, then it doesn't work right. What a pain.

Sorry for spamming this up. I think I got it though! If you wrap the select element in a span, and use this CSS on the wrapper (and remove the display:none on the select element):

width: 0px;
height: 0px;
overflow: hidden;
display: inline-block;
position: absolute;

You will get the error message and no break the page flow at the same time. The only problem is you have to leave the box visible in order to see the error message because Firefox and WebKit will hide the message if you don't. This causes the select box to receive tabs through the form.

The way around that might be to toggle display from none to inline-block on submit (or the 'invalid' event), then toggle it back on certain input events (like mouse down or keypress).

There is also a small positioning issue, resolvable by forcing the position to be directly under the chosen box.

Would be nice to see some kind of built-in support for this, if possible at all.

I wrote a patch here: https://github.com/adcSTUDIO/chosen

It may not be robust enough for inclusion, but feel free to test it out.

Thanks @CaptainN! I'll check it out!

@CaptainN, I got it working - thanks for making those changes. However, do you know how to allow the width of the error popups to exceed the width of the select boxes themselves? On some of my smaller select elements, the error message is really thin which doesn't exactly look very good, and can even be hard to read on some.

If not, that's ok, you've already helped a ton with this. Thanks again!

@caderade I'm not sure how to fix that problem. I tried overflow:visible and a couple of other things, and it still shows up short I'll try a few more things, but this looks like a problem with Firefox that may not have a workaround (these flags are generally pretty hard to deal with, along with that glow, which I haven't yet found a way to style completely).

@CaptainN: Very nice.

It works pretty well for me in Firefox 17 and Chrome 23.

In IE 8+9 (which don't support HTML5 form validation at all), when changing the value of the field, I get a JavaScript error because of the unknown :valid selector being used. Thus the script is aborted and the form doesn't get uglified in any way, which I expected in IE. :smirk: Not raising an error would be nicer, though. Any idea?

Oh bother. I actually figure jQuery would protect me more! I'll have to add an IE check or something...

Kevin N.

@CaptainN It has the issue for me in Chrome as well. Wasn't sure if you thought it was a Firefox issue only or not. But dude, thanks a ton again man. Awesome work! Let us know if you are ever able to address the width thing though.

It looks like jQuery has some built in pseudo selector support, and a hooks system so plugins can add their own, and if it doesn't find any, it passes it on to the underlying implementation - so :required and :valid throw an error in IE (and probably some versions of Safari) if they haven't been polyfilled. I'll see if I can throw an alternative kind of check in there, instead of using the pseudo selectors. It looks like I can just check attr("required") to replace :required - I'll probably have to do some kind of feature detect for :valid though - maybe a check for a .oninvalid property?

Ok, I got a new patch up that fixes the IE error (and should fix it in any other browsers too). This patch changes a few things (nothing you should notice). Here are my notes:

  • matched the coding style of event handlers present in jquery version (bind instead of on, etc.)
  • I can't get the prototype version to hide the select element when validated - it looks like the form element's change event is being suppressed somehow (it works otherwise) - I think this is a bug, but not one I introduced. Need to investigate further.
  • There are some minor quirks about the positioning of the invalid element that may sometimes need manual intervention by the user through CSS (only a problem if required feature is used).
  • short widthed select boxes end up with smooshed required flags in the browser (also a problem with vanilla select elelements if you set the width through css). I can't find a workaround (let me know if you do!) Maybe take it up with Mozilla, since it'll happen with vanilla boxes too. Also, maybe check out their css extensions? https://developer.mozilla.org/en-US/docs/CSS/CSS_Reference/Mozilla_Extensions?redirectlocale=en-US&redirectslug=CSS_Reference%2FMozilla_Extensions (I couldn't find anything at a glance)
  • I can't get uglifyjs to work on Windows (so the .min.js builds aren't updated in my repo) - I'll try a build from OSX tomorrow.

@CaptainN For your issue with UglifyJS, make sure you install the version 1 as the version 2 is not BC. #915 is updating the packages.json

How do I switch the version using npm?

@CaptainN npm install uglify-js@1 to force the version 1 IIRC (but I'm not a node expert). The other solution is to checkout my branch and running npm install with the updated packages.json file.

I was able to build the uglified versions on my work mac (maybe it has an older version of uglify-js?). They are now up to date in my repo.

I'm only using the jQuery flavor currently. No script error in IE8/9 anymore. :+1: for seeing this feature in upstream soon.

We are also facing this issue. Is there a workaround except disabling HTML5 validation?
@CaptainN fixed it from what I read. So I tried his chosen.jquery.js file in master branch. But it gives js error of msie undefined.

I thought I fixed that. That fork was a while ago, and may need to be updated. I'll see if I can get to that this week, and look into the IE bug.

I synced this upstream, and I didn't see any undefined error notices in IE. Try my repo again, and let me know if you still see this problem. (sorry it took so long)

Thanks!

:+1:

Could someone sum this up for me? Is there a fork or a patch around that is ready for production?

There is a pull request that goes along with this - #900 which would pull my adcSTUDIO/Chosen fork.

Instead of hiding the original select box - when the select is required, and when there is an error, the patch positions the select box underneath the Chosen select box, so that the built in HTML5 error message appears in the correct location. Edit: I should probably note that if the box is not marked as "required" and is never invalidated, the existing behavior is preserved.

This pull request doesn't add any additional functionality outside of making the built in HTML5 error notices display.

Thanks Kevin!

2013/7/29 Kevin Newman [email protected]

There is a pull request that goes along with this - #900https://github.com/harvesthq/chosen/issues/900which would pull my adcSTUDIO/Chosen fork.

Instead of hiding the original select box - when the select is required,
and when there is an error, the patch positions the select box underneath
the Chosen select box, so that the built in HTML5 error message appears in
the correct location.

This pull request doesn't add any additional functionality outside of
making the built in HTML5 error notices display.


Reply to this email directly or view it on GitHubhttps://github.com/harvesthq/chosen/issues/515#issuecomment-21750086
.

Urs Bräm
macht Websites

lic. phil. I

Theaterplatz 2
3011 Bern
Tel. Büro: +41 31 311 73 61
Tel. Mobil & Combox: +41 76 327 01 51
http://www.ursbraem.ch

Privat:
Beundenfeldstr. 50
3013 Bern
P +41 31 301 41 90

Hi,
I just got the latest version (1.0) and I'm still experiencing this problem. When chosen is added to a select box with the required attribute, in Firefox the "please select an item from the list" tool tip appears in the top left corner of the screen. In Chrome nothing happens at all. Is the pull request not integrated with version 1.0? How can I download that patch? Sorry I'm not more familiar with Github and thanks in advance!

I don't think my changes were merged. My fork probably need to be updated too - it's been a while.

Ah, that's too bad. Any idea if it's on the master branch pipeline? Any suggestions for getting this to work in the meantime?

I have no idea if they plan to integrate this into master, but what you can do is use my fork, and sync it to master, and that'll get you an update to date pull from their repo, with my changes applied (assuming no conflicts) - or just use my somewhat outdated fork. Unfortunately, I won't have the time to update my fork in the near term.

Thanks, Kevin.


Yaron Guez
Chief Software Architect
MedAdaptics - http://medadaptics.com
(781) 767-7434

On Wed, Nov 27, 2013 at 12:35 PM, Kevin Newman [email protected]:

Here is my fork btw: https://github.com/adcSTUDIO/chosen


Reply to this email directly or view it on GitHubhttps://github.com/harvesthq/chosen/issues/515#issuecomment-29403732
.

@CaptainN Have you opened a PR with your changes ? I don't see any link to a PR in this discussion. And if there is no PR to review it, it is unlikely that your fork will be reviewed (maintainers review submitted contributions, which already requires time, so they won't try to find unsubmitted contributions)

There is a PR #900 - it's a bit of a mess - I could probably rebase it at some point, and clean that up if it would help.

<select required> attribute support for chosen plugin

Hello!
Everything is very, very simple, and you do not need to have 2 years to discuss it :)
@CaptainN @yaronguez @stof @kenearley

To adding correct displaying a browser error message with chosen for <select required> when user don't pick any option,

  1. Remove display:none setting for select tag from plugin JS code.
  2. Wrap in <select> tag in wrapping <div>, then add CSS position: relative; for this <div> in your CSS.
  3. Add position: absolute; clip: rect (0,0,0,0); to hide the <select> tag in plugin JS code.

If you do not want to spend time editing the plugin code, just add something like setAttribute ('style', 'display: visible; position: absolute; clip: rect (0,0,0,0)'); after initializing the chosen plugin.

Example:

function InitChosen() {
    $('select.chzn').each(function(index) {
        $(this).chosen({
            disable_search_threshold: 5,
            no_results_text: "Ничего не найдено!"
        });
        this.setAttribute('style','display:visible; position:absolute; clip:rect(0,0,0,0)');
    });
}

That's all. Aaaaaand now... DISCO! :)
** For browsers which supports "required" attribute.

Chrome

--2

FireFox

--1

@Aharito Won't we hit the tab-order problem by doign this?

Thanks @Aharito it's working great with chosen v1.1.0, just replace $('select.chzn') with $('.chosen-select').

I thought I tried that clip: rect trick, and found some issue with it. Maybe with an older browser? I guess if its working now that's great.

I think there may be tab issues with my solution as well (I can't remember, it's been a while) - I reduced the impact by only applying the patch to fields that poses the required attribute.

We've standardised this across all calls to $().chosen()

$.fn.oldChosen = $.fn.chosen
$.fn.chosen = function(options) {
  var select = $(this)
    , is_creating_chosen = !options || _.isObject(options)

  if (is_creating_chosen && select.css('position') === 'absolute') {
    // if we are creating a chosen and the select already has the appropriate styles added
    // we remove those (so that the select hasn't got a crazy width), then create the chosen
    // then we re-add them later
    select.removeAttr('style')
  }

  var ret = select.oldChosen(options)

  if (is_creating_chosen) {
    // https://github.com/harvesthq/chosen/issues/515#issuecomment-33214050
    // only do this if we are initializing chosen (no params, or object params) not calling a method
    select.attr('style','display:visible; position:absolute; clip:rect(0,0,0,0)');
  }
  return ret
}

@ghiculescu That doesn't solve the problem of tabbing or shift-tabbing into the select, does it?

@DASPRiD nope.

what about this as a possible cover up solution.

it's not perfect, but in fact, it stops the original select from appearing by passing the focus to the next chosen dialog box, but perhaps it's another step closer

"chosen-select" is just a selector for the selects I have with a particular class, I'm not sure whether "click focus" covers all the respective events I should hook onto, but maybe somebody can say what else is missing?

it's also possible that I've misunderstood something about the chosen html structure and find("a") is too liberal, anybody have more experience?

$(".chosen-select").on("click focus",function(event){
    $(this).next(".chosen-container").find("a").trigger(event.type);
});

oh, and surely "display:visible" should be "display:block" or something? cause visibility:visible is valid, but display:visible I'm sure is not

what I found is that if you have multiple selects next to each other in the same container, this displaces them all into the wrong location so the position: absolute then makes the validation message appear in the wrong position.

I solved this by detaching and reattaching into the chosen-container, like so

$(".chosen-select").each(function(){
    $(this).next(".chosen-container").prepend($(this).detach());
});

the above solution, after more investigation, shows that it disables tabbing through the fields completely and I'm unable to solve the problem, however it does eliminate the problem of the select popping up when you're tabbing through, so that is the more important problem in my mind, I can live without tabbing if I can have it so it doesn't break the display, seeing as more people are using mobile devices and aren't tabbing anyway, it only affects desktop users, still important, but relatively speaking, managable.

however, if anybody solves that by some way, I'm very interested to find out.

ok, so further to what I was trying before, I found the events chosen was using and decided that when I did any event on the now hidden select, I could hijack it and trigger a chosen event to open it up.

i think it works nicely.

$(".chosen-select").each(function(){
    //    take each select and put it as a child of the chosen container
    //    this mean it'll position any validation messages correctly
    $(this).next(".chosen-container").prepend($(this).detach());

    //    apply all the styles, personally, I've added this to my stylesheet
    $(this).attr("style","display:block!important; position:absolute; clip:rect(0,0,0,0)");

    //    to all of these events, trigger the chosen to open and receive focus
    $(this).on("click focus keyup",function(event){
        $(this).closest(".chosen-container").trigger("mousedown.chosen");
    });
});

I think this is the best version I've got so far. Happily this solves the forward-tabbing problem, there is still the reverse tabbing, you can't tab backwards through a chosen-select because the second you tab into the select element, you immediately refocus into the chosen-container again, meaning you're trapped into only being able to tab forwards.

It might be an idea to keep track of the previous element and if the element that previously had tab focus was in front of the current focused element, you're going backwards, then appropriately skip refocusing to the chosen and select the previous tab, but i'm unsure how to do that.

After a very long read, I thought I tried the suggestions submitted throughout the years.

Unfortunately, I couldn't get the code by @christhomas to work. I invoke it within a submit function with no visible results (no errors either).

Good news is the new function by @ghiculescu works like a treat as I can still use the CDN chosen file and just use the function in my js file.

@DASPRiD @charettes what do you mean tab doesn't work with the modified function? It seems to be working for me

Easy enough to add tabindex: -1 to the select to @ghiculescu 's snippet, solving the tabbing problem.

Example: http://jsfiddle.net/hq7b426j/

I could see the problem now! Your addition works great @andreialecu

There was one other addition needed by the way. On iPhone, or other unsupported devices, the fiddle wouldn't work properly. Chosen disables itself on iPhone and leaves the <select> unchanged, and the code in the fiddle above would hide it, leaving no way to interact with the select.

This fiddle fixes it (by adding a display: none check):
http://jsfiddle.net/hq7b426j/1/

Ah that's even better!! Thanks! I'm still testing too, but I'll post if anything else comes up

@CaptainN please brief i have same issue. wr i need to put that code. i am using inspina theme from wrapbootstrap.

@vidhyaprakash85 I'm not sure what you mean. I had forked a long while ago, and wrote a pull request (#900) but the repos are out of sync now, and my fork is very out of date. You can findit here if it helps: https://github.com/adcSTUDIO/chosen

i am already using https://github.com/harvesthq/chosen how to do that :(

@andreialecu your code works fine! thanks!!!

Thanks @christhomas your code worked great :dancer:

Neither @christhomas or @ghiculescu worked for me using a multi-grouped select. leaving it to server validation for now.

When I tried I the @ghiculescu patch, it worked except a scroll was displayed all the time, below the select box.
When I tried the @christhomas patch the popup appeared without the search box opening.

I had to modify @ghiculescu 's script so I could call chosen twice as such:

target.find('select')
        .chosen('destroy')
        .chosen({disable_search_threshold: 10})

Otherwise, 2nd trip removed the style that was added in the first:

$.fn.oldChosen = $.fn.chosen
$.fn.chosen = function(options) {
  var select = $(this)
    , is_creating_chosen = !!options

    var style = 'display:visible; position:absolute; clip:rect(0,0,0,0);'

        if (is_creating_chosen && select.css('position') === 'absolute' && select.attr('style') != style) {
            // if we are creating a chosen and the select already has the appropriate styles added
            // we remove those (so that the select hasn't got a crazy width), then create the chosen
            // then we re-add them later
            select.removeAttr('style')
        }

        var ret = select.oldChosen(options)

        // only act if the select has display: none, otherwise chosen is unsupported (iPhone, etc)
        if (is_creating_chosen && select.css('display') === 'none') {
            // https://github.com/harvesthq/chosen/issues/515#issuecomment-33214050
            // only do this if we are initializing chosen (no params, or object params) not calling a method
            select.attr('style', style);
            select.attr('tabindex', -1);
        }
        return ret
}

I just added this extra condition to the 1st if: && select.attr('style') != style

@doganmeh Works great in Chrome and mobile (with Chrome) but tested in Firefox 53.0 where it does not work

Even this http://jsfiddle.net/hq7b426j/1/ does not work in Firefox 53.0

Hmmm, but this seems more like a Firefox problem because if you click on the button more times, you will see that Firefox tries to display the message (but such is never rendered completely)

I've used this solution. It is very simple and works perfect:

<style>
    select.submitted:invalid + .chosen-container{
        border-color: red !important;
    }
</style>
$('#yourSelector').chosen({
                no_results_text: "yourText",
                disable_search_threshold: 9,
                search_contains: true
                //your parameters
    }).on('invalid', function(){
        $(this).addClass('submitted');
    });

it seems that this doesn't work if you have chosen with multiple selections :
http://jsfiddle.net/jeromax/o5a8aogh/

I fixed it.

`
$.fn.oldChosen = $.fn.chosen
$.fn.chosen = function (options) {
var select = $(this),
is_creating_chosen = !!options;

if (is_creating_chosen && select.css('position') === 'absolute') {
// if we are creating a chosen and the select already has the appropriate styles added
// we remove those (so that the select hasn't got a crazy width), then create the chosen
// then we re-add them later
select.removeAttr('style');
}

var ret = select.oldChosen(options)

// only act if the select has display: none, otherwise chosen is unsupported (iPhone, etc)
if (is_creating_chosen && select.css('display') === 'none') {
// https://github.com/harvesthq/chosen/issues/515#issuecomment-33214050
// only do this if we are initializing chosen (no params, or object params) not calling a method

  $(this).each(function(index){
      if($(this)[0].multiple==true){
          $(this).attr('style','display:visible; width:0px; height:0px; margin-top:25px; position:absolute; clip:rect(0,0,0,0)');
      }else{
          $(this).attr("style","display:visible; position:absolute; clip:rect(0,0,0,0)");
      }
  })

select.attr('tabindex', -2);

}
return ret
}
`

+1

Can somebody commit a fix for this? It's pretty old issue and very important functionality nowadays. Thank you.

Not working on latest version.

This seems to be breaking angular.js form validation when using angular-chosen too.

It's 2018 and we're still having the same issue. It's a hell how HTML standards cannot work properly and integrated with external plugins. Crazy times :)

This is breaking Drupal's chosen plugin as well. See https://www.drupal.org/project/chosen/issues/2705891

Couldn't find any proper solution to this other than a workaround:

<div class="form__select">
  <select class="chosen">
    <!-- options -->
  </select>
</div>
.form__select {
    position: relative;
}

.form__select .chosen {
    display: block !important;
    height: 0;

    position: absolute;
    left: 35px;
    bottom: 0;

    outline: none;
    border-color: white;

    pointer-events: none;
}

If you're using Chosen for all select elements, you can use this CSS to change make it visible (to DOM), but no opacity, no height, absolute position.

These CSS selectors target invalid select elements, with one of them targeting multiple adding a 15px margin-top to center it on the multiselect elements.

select:invalid {
    height: 0px !important;
    opacity: 0 !important;
    position: absolute !important;
    display: flex !important;
}

select:invalid[multiple] {
   margin-top: 15px !important;
}

Demo: http://jsfiddle.net/tripflex/2zdeu9oc/

BUT REALLY ... this should already be handled by the Chosen.JS lib

Here's my workaround, if it's of any use:

// Initialise Chosen
$(function () {
    $('select').chosen();
});

// Place the original input behind the Chosen input, matching the height and width so that the warning appears in the correct position
$('select').on('chosen:ready', function () {
    const height = $(this).next('.chosen-container').height();
    const width = $(this).next('.chosen-container').width();

    $(this).css({
            'position': 'absolute',
            'height': height,
            'width': width,
            'opacity': 0
        })
        .show();
});

@jonathanbull can you show it within context? I tried your solution and it didn't work.

@AndrewSouthpaw This is my code, fixs works fine for me :)

$("#select").val([]); // disable default selection by browser
$('#select').on('chosen:ready', function(evt, params, chosen) {
    $(this).css({'position': 'absolute', 'height': 0, 'opacity': 0}).show();
});
$("#select").chosen();

I'm using a slight different code (based on the code here):

$('.chosen-select').on("chosen:ready", function (evt, data) {
  $(this)
    .addClass('chosen_hidden')
    .attr('tabindex', '-1')
    .prependTo(data.chosen.container)
    .show()
  })
  .chosen({width: '100%'})
.chosen_hidden {
  position: absolute;
  top: 0;
  bottom: 0;
  max-height: 100%; // required for IE 10
  // **not required** opacity: 0;
}

It does not handle the 'destroy' action, but it does position the error message nicely and seems to work on Firefox and Chromiun. As the original selector is not hidden, the error highlight border is visible. Update: with max-height it also works on IE. Other update: add tabindex -1 to make sure it does not receive focus. (while still being focusable and receive error messages).

There has been an open PR that resolves this, but I think it got lost since the other thread it targeted was closed. See #2594

@jhedstrom would love to see that merged. Do you know if this library is still maintained?

I used something similar to @eloyesp's solution above and shared that here:

https://github.com/harvesthq/chosen/pull/2594#issuecomment-714806139

Thanks @jhedstrom for pointing me in the right direction!

Was this page helpful?
0 / 5 - 0 ratings