<p:selectOneMenu> generates input field behind select box

4.3k views Asked by At

I'm trying to associate a label tag with my dropdown menu to make it accessible to screen readers. I've noticed that when using p:selectOneMenu primefaces generates an input element that should not be there. When applying p:outputLabel, it appears to work fine (ie you click on the label text and focus moves to the dropdown menu). However it turns out that the focus is in fact moving to the input element and the select element is not keyboard accessible (tabindex="-1"). Here's an example taken from the primefaces website: http://www.primefaces.org/showcase/ui/input/oneMenu.xhtml

<h:form>
<p:messages autoUpdate="true" />

<h:panelGrid columns="2" style="margin-bottom:10px" cellpadding="5">
    <p:outputLabel for="console" value="Basic:" />
    <p:selectOneMenu id="console" value="#{selectOneMenuView.console}" style="width:125px">
        <f:selectItem itemLabel="Select One" itemValue="" />
        <f:selectItem itemLabel="Xbox One" itemValue="Xbox One" />
        <f:selectItem itemLabel="PS4" itemValue="PS4" />
        <f:selectItem itemLabel="Wii U" itemValue="Wii U" />
    </p:selectOneMenu>

    <p:outputLabel for="car" value="Grouping: " />
    <p:selectOneMenu id="car" value="#{selectOneMenuView.car}">
        <f:selectItem itemLabel="Select One" itemValue="" />
        <f:selectItems value="#{selectOneMenuView.cars}" />
    </p:selectOneMenu>

    <p:outputLabel for="city" value="Editable: " />
    <p:selectOneMenu id="city" value="#{selectOneMenuView.city}" effect="fold" editable="true">
        <f:selectItem itemLabel="Select One" itemValue="" />
        <f:selectItems value="#{selectOneMenuView.cities}" />
    </p:selectOneMenu>

    <p:outputLabel for="advanced" value="Advanced:"  />
    <p:selectOneMenu id="advanced" value="#{selectOneMenuView.theme}" converter="themeConverter" panelStyle="width:180px"
                     effect="fade" var="t" style="width:160px" filter="true" filterMatchMode="startsWith">
        <f:selectItems value="#{selectOneMenuView.themes}" var="theme" itemLabel="#{theme.displayName}" itemValue="#{theme}" />

        <p:column style="width:10%">
            <h:outputText styleClass="ui-theme ui-theme-#{t.name}" />
        </p:column>

        <p:column>
            <h:outputText value="#{t.displayName}" />
        </p:column>
    </p:selectOneMenu>
</h:panelGrid>

<p:commandButton value="Submit" update="display" oncomplete="PF('dlg').show()" icon="ui-icon-check" />

<p:dialog header="Values" modal="true" showEffect="bounce" widgetVar="dlg" resizable="false">
    <p:panelGrid columns="2" id="display" columnClasses="label,value">
        <h:outputText value="Basic:" />
        <h:outputText value="#{selectOneMenuView.console}" />

        <h:outputText value="Grouping:" />
        <h:outputText value="#{selectOneMenuView.car}" />

        <h:outputText value="Editable" />
        <h:outputText value="#{selectOneMenuView.city}" />

        <h:outputText value="Advanced:" />
        <h:outputText value="#{selectOneMenuView.theme.displayName}" />
    </p:panelGrid>
</p:dialog>

When you look at the page with just the html loaded, you can see each p:selectOneMenu generates an input as well as a select.

<td>
    <label id="j_idt88:j_idt91" class="ui-outputlabel ui-widget" for="j_idt88:console_focus">Basic:</label>
</td>
<div id="j_idt88:console" class="ui-selectonemenu ui-widget ui-state-default ui-corner-all" style="width:125px">
<div class="ui-helper-hidden-accessible">
    <input id="j_idt88:console_focus" name="j_idt88:console_focus" type="text" autocomplete="off">
</div>
<div class="ui-helper-hidden-accessible">
<select id="j_idt88:console_input" name="j_idt88:console_input" tabindex="-1" data-p-label="Basic" data-p-hl="onemenu">
<option value="">Select One</option><option value="Xbox One">Xbox One</option>
<option value="PS4">PS4</option>
<option value="Wii U">Wii U</option>
</select>
</div>
<label id="j_idt88:console_label" class="ui-selectonemenu-label ui-inputfield ui-corner-all">Select One</label>
<div class="ui-selectonemenu-trigger ui-state-default ui-corner-right">
<span class="ui-icon ui-icon-triangle-1-s ui-c"></span>
</div>
</div>

I'm looking to have the dropdown menu to behave like the JSF one h:selectOneMenu (when it comes to accessibility). Specific to the example, I want the "Basic:" label associated with it's dropdown menu so that when you click "Basic" focus moves to the dropdown menu. I also want a screen reader to actually treat it as a select element rather than an input element. So far I can't find a way to do this because of that input element that's generated. I'm currently using Primefaces 5.2. Does anyone know a way to prevent this input element from being generated?

1

There are 1 answers

3
ForguesR On BEST ANSWER

I gave up on the p:selectOneMenu for two reasons : it is not accessible and it is a pain to use on a mobile device because it doesn't bring the native control picker (the "spinning wheel" on the iPad for instance).

Instead I use the h:selectOneMenu customized with something like :

<h:selectOneMenu
  styleClass="ui-inputfield ui-widget ui-state-default ui-corner-all #{component.valid ? '' : 'ui-state-error'}"
  onmouseover="$(this).addClass('ui-state-active')"
  onmouseout="$(this).removeClass('ui-state-active')"
  onfocus="$(this).addClass('ui-state-active ui-state-focus')"
  onblur="$(this).removeClass('ui-state-active ui-state-focus')"/>

It doesn't look that bad, it is accessible and it works well with mobile device.