SelectOneMenu is used to choose a single item from a list.
An item with an empty itemLabel has no text for a screen reader to announce. Such an item
is rendered with the localized nullLabel ARIA label ("Not Selected"), both in the options
list and on the closed menu once it is selected. A label that only looks blank, such as a single space,
and a noSelectionOption item are treated the same way. When a placeholder is
set, the placeholder is the visible text and is announced instead. With
hideNoSelectionOption="true" the no-selection item is not rendered at all, so there is
nothing left to announce.
<div class="card">
<h:form>
<div class="ui-fluid formgrid grid">
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Basic"/>
<p:selectOneMenu id="option" value="#{selectOneMenuView.selectedOption}">
<f:selectItem itemLabel="Select One" itemValue=""/>
<f:selectItem itemLabel="Option1" itemValue="Option1"/>
<f:selectItem itemLabel="Option2" itemValue="Option2"/>
<f:selectItem itemLabel="Option3" itemValue="Option3"/>
<f:facet name="footer">
<p:divider styleClass="mt-0" />
<h:outputText value="3 options" style="font-weight:bold;"/>
</f:facet>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Grouping"/>
<p:selectOneMenu id="group" value="#{selectOneMenuView.countryGroup}">
<f:selectItem itemLabel="Select One" itemValue=""/>
<f:selectItems value="#{selectOneMenuView.countriesGroup}"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Editable"/>
<p:selectOneMenu id="city" value="#{selectOneMenuView.city}" editable="true">
<f:selectItem itemLabel="Select One" itemValue=""/>
<f:selectItems value="#{selectOneMenuView.cities}"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel value="Label"/>
<p:selectOneMenu id="labeled" value="#{selectOneMenuView.labeled}" label="Always Display Label"
alwaysDisplayLabel="true">
<f:selectItems value="#{selectOneMenuView.cities}"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Advanced"/>
<p:selectOneMenu id="advanced" value="#{selectOneMenuView.country}" converter="#{countryConverter}"
panelStyle="width:180px" var="c"
filter="true" filterMatchMode="startsWith" filterNormalize="true">
<f:selectItems value="#{selectOneMenuView.countries}" var="country"
itemLabel="#{country.name}" itemValue="#{country}"/>
<p:column style="width:10%">
<span class="flag flag-#{c.code}" style="width: 30px; height: 20px"/>
</p:column>
<p:column>
<f:facet name="header">
<h:outputText value="Name"/>
</f:facet>
<h:outputText value="#{c.name}"/>
</p:column>
<f:facet name="footer">
<h:outputText value="#{selectOneMenuView.countries.size()} countries"
style="font-weight:bold;" styleClass="py-1 block"/>
</f:facet>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Lazy"/>
<p:selectOneMenu id="lazy" value="#{selectOneMenuView.option}" dynamic="true">
<f:selectItem itemLabel="Select One" itemValue=""/>
<f:selectItems value="#{selectOneMenuView.options}"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Hide NoSelection Option"/>
<p:selectOneMenu id="hideNoselectionOption" value="#{selectOneMenuView.hideNoSelectOption}"
hideNoSelectionOption="#{not empty selectOneMenuView.hideNoSelectOption}">
<p:ajax update="@this" process="@this"/>
<f:selectItem itemLabel="Select One" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItem itemLabel="Option1" itemValue="Option1"/>
<f:selectItem itemLabel="Option2" itemValue="Option2"/>
<f:selectItem itemLabel="Option3" itemValue="Option3"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Long Item Label"/>
<p:selectOneMenu id="longItemLabel" value="#{selectOneMenuView.longItemLabel}">
<f:selectItem itemLabel="Zero" itemValue="0"/>
<f:selectItem itemLabel="One" itemValue="1"/>
<f:selectItem itemLabel="Two" itemValue="2"/>
<f:selectItem itemLabel="Three" itemValue="3"/>
<f:selectItem itemLabel="Four" itemValue="4"/>
<f:selectItem itemLabel="Five" itemValue="5"/>
<f:selectItem itemLabel="Six" itemValue="6"/>
<f:selectItem itemLabel="Seven" itemValue="7"/>
<f:selectItem itemLabel="Long item here not necessary in the end" itemValue="99"/>
<f:selectItem itemLabel="Eight" itemValue="8"/>
<f:selectItem itemLabel="Nine" itemValue="9"/>
<f:selectItem itemLabel="Ten and not more than ten " itemValue="10"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="RTL"/>
<p:selectOneMenu id="trl" value="#{selectOneMenuView.rtl}" dir="rtl">
<f:selectItem itemLabel="Select One" itemValue=""/>
<f:selectItem itemLabel="Option1" itemValue="Option1"/>
<f:selectItem itemLabel="Option2" itemValue="Option2"/>
<f:selectItem itemLabel="Option3" itemValue="Option3"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="selectOneMenuIcon" value="Icons" />
<h:panelGroup styleClass="ui-inputgroup">
<h:panelGroup id="icon" styleClass="ui-inputgroup-addon">
<i class="pi pi-#{selectOneMenuView.icon}"/>
</h:panelGroup>
<p:selectOneMenu id="selectOneMenuIcon" value="#{selectOneMenuView.icon}" var="item">
<f:selectItems value="#{['flag','wallet','map','link']}" var="item" itemLabel="#{item}"
itemValue="#{item}" />
<p:column><i class="pi pi-#{item}" /> #{item} </p:column>
<p:ajax update="@parent:@parent:icon" />
</p:selectOneMenu>
</h:panelGroup>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Disabled"/>
<p:selectOneMenu id="disabled" value="#{selectOneMenuView.selectedOption}" disabled="true">
<f:selectItem itemLabel="Select One" itemValue=""/>
<f:selectItem itemLabel="Option1" itemValue="Option1"/>
<f:selectItem itemLabel="Option2" itemValue="Option2"/>
<f:selectItem itemLabel="Option3" itemValue="Option3"/>
</p:selectOneMenu>
</div>
</div>
</h:form>
</div>
<div class="card">
<h5 class="mt-0">Empty Item Label</h5>
<p>
An item with an empty <code>itemLabel</code> has no text for a screen reader to announce. Such an item
is rendered with the localized <code>nullLabel</code> ARIA label ("Not Selected"), both in the options
list and on the closed menu once it is selected. A label that only looks blank, such as a single space,
and a <code>noSelectionOption</code> item are treated the same way. When a <code>placeholder</code> is
set, the placeholder is the visible text and is announced instead. With
<code>hideNoSelectionOption="true"</code> the no-selection item is not rendered at all, so there is
nothing left to announce.
</p>
<h:form>
<div class="ui-fluid formgrid grid">
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Empty Item Label"/>
<p:selectOneMenu id="emptyItem" value="#{selectOneMenuView.emptyItem}">
<f:selectItem itemLabel="" itemValue=""/>
<f:selectItem itemLabel="Yes" itemValue="true"/>
<f:selectItem itemLabel="No" itemValue="false"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Blank Item Label"/>
<p:selectOneMenu id="blankItem" value="#{selectOneMenuView.blankItem}">
<f:selectItem itemLabel=" " itemValue=""/>
<f:selectItem itemLabel="Yes" itemValue="true"/>
<f:selectItem itemLabel="No" itemValue="false"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Empty Item Label with Placeholder"/>
<p:selectOneMenu id="emptyItemPlaceholder" value="#{selectOneMenuView.emptyItemWithPlaceholder}"
placeholder="Choose One">
<f:selectItem itemLabel="" itemValue=""/>
<f:selectItem itemLabel="Yes" itemValue="true"/>
<f:selectItem itemLabel="No" itemValue="false"/>
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<p:outputLabel for="@next" value="Empty NoSelection Option"/>
<p:selectOneMenu id="emptyNoSelectionItem" value="#{selectOneMenuView.emptyNoSelectionItem}">
<f:selectItem itemLabel="" itemValue="#{null}" noSelectionOption="true"/>
<f:selectItem itemLabel="Yes" itemValue="true"/>
<f:selectItem itemLabel="No" itemValue="false"/>
</p:selectOneMenu>
</div>
</div>
</h:form>
</div>
package org.primefaces.showcase.view.input;
import org.primefaces.showcase.domain.Country;
import org.primefaces.showcase.service.CountryService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.model.SelectItem;
import jakarta.faces.model.SelectItemGroup;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@Named
@RequestScoped
public class SelectOneMenuView {
private String selectedOption;
private String rtl;
private String hideNoSelectOption;
private String countryGroup;
private List<SelectItem> countriesGroup;
private String city;
private Map<String, String> cities = new HashMap<>();
private Country country;
private List<Country> countries;
private String option;
private List<String> options;
private String longItemLabel;
private String labeled;
private String icon = "flag";
private String emptyItem;
private String blankItem;
private String emptyItemWithPlaceholder;
private String emptyNoSelectionItem;
@Inject
private CountryService service;
@PostConstruct
public void init() {
countriesGroup = new ArrayList<>();
SelectItemGroup europeCountries = new SelectItemGroup("Europe Countries");
europeCountries.setSelectItems(new SelectItem[]{
new SelectItem("Germany", "Germany"),
new SelectItem("Greece", "Greece"),
new SelectItem("Turkey", "Turkey"),
new SelectItem("Slovakia", "Slovakia"),
new SelectItem("Slovenia", "Slovenia"),
new SelectItem("Spain", "Spain")
});
SelectItemGroup americaCountries = new SelectItemGroup("America Countries");
americaCountries.setSelectItems(new SelectItem[]{
new SelectItem("United States", "United States"),
new SelectItem("Brazil", "Brazil"),
new SelectItem("Mexico", "Mexico")
});
countriesGroup.add(europeCountries);
countriesGroup.add(americaCountries);
//cities
cities = new HashMap<>();
cities.put("New York", "New York");
cities.put("London", "London");
cities.put("Paris", "Paris");
cities.put("Barcelona", "Barcelona");
cities.put("Istanbul", "Istanbul");
cities.put("Berlin", "Berlin");
//countries
countries = service.getCountries();
//options
options = new ArrayList<>();
for (int i = 0; i < 20; i++) {
options.add("Option " + i);
}
}
public String getSelectedOption() {
return selectedOption;
}
public void setSelectedOption(String selectedOption) {
this.selectedOption = selectedOption;
}
public String getRtl() {
return rtl;
}
public String getHideNoSelectOption() {
return hideNoSelectOption;
}
public void setHideNoSelectOption(String hideNoSelectOption) {
this.hideNoSelectOption = hideNoSelectOption;
}
public void setRtl(String rtl) {
this.rtl = rtl;
}
public String getCountryGroup() {
return countryGroup;
}
public void setCountryGroup(String countryGroup) {
this.countryGroup = countryGroup;
}
public List<SelectItem> getCountriesGroup() {
return countriesGroup;
}
public void setCountriesGroup(List<SelectItem> countriesGroup) {
this.countriesGroup = countriesGroup;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Map<String, String> getCities() {
return cities;
}
public void setCities(Map<String, String> cities) {
this.cities = cities;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
public List<Country> getCountries() {
return countries;
}
public String getOption() {
return option;
}
public void setOption(String option) {
this.option = option;
}
public List<String> getOptions() {
return options;
}
public void setOptions(List<String> options) {
this.options = options;
}
public String getLongItemLabel() {
return longItemLabel;
}
public void setLongItemLabel(String longItemLabel) {
this.longItemLabel = longItemLabel;
}
public String getLabeled() {
return labeled;
}
public void setLabeled(String labeled) {
this.labeled = labeled;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getEmptyItem() {
return emptyItem;
}
public void setEmptyItem(String emptyItem) {
this.emptyItem = emptyItem;
}
public String getBlankItem() {
return blankItem;
}
public void setBlankItem(String blankItem) {
this.blankItem = blankItem;
}
public String getEmptyItemWithPlaceholder() {
return emptyItemWithPlaceholder;
}
public void setEmptyItemWithPlaceholder(String emptyItemWithPlaceholder) {
this.emptyItemWithPlaceholder = emptyItemWithPlaceholder;
}
public String getEmptyNoSelectionItem() {
return emptyNoSelectionItem;
}
public void setEmptyNoSelectionItem(String emptyNoSelectionItem) {
this.emptyNoSelectionItem = emptyNoSelectionItem;
}
public void setService(CountryService service) {
this.service = service;
}
}
package org.primefaces.showcase.domain;
import java.io.Serializable;
import java.util.Locale;
import java.util.Objects;
public class Country implements Serializable, Comparable<Country> {
private int id;
private String name;
private String code;
private Locale locale;
private boolean rtl;
public Country() {
}
public Country(int id, Locale locale) {
this(id, locale.getDisplayCountry(), locale.getCountry().toLowerCase(), locale);
}
public Country(int id, Locale locale, boolean rtl) {
this(id, locale.getDisplayCountry(), locale.getCountry().toLowerCase(), locale);
this.rtl = rtl;
}
public Country(int id, String name, String code) {
this(id, name, code, null);
}
public Country(int id, String name, String code, Locale locale) {
this.id = id;
this.name = name;
this.code = code;
this.locale = locale;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Locale getLocale() {
return locale;
}
public void setLocale(Locale locale) {
this.locale = locale;
}
public String getLanguage() {
return locale == null ? "en" : locale.getLanguage();
}
public String getDisplayLanguage() {
return locale == null ? "English" : locale.getDisplayLanguage();
}
public boolean isRtl() {
return rtl;
}
public void setRtl(boolean rtl) {
this.rtl = rtl;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Country country = (Country) o;
return id == country.id
&& Objects.equals(name, country.name)
&& Objects.equals(code, country.code);
}
@Override
public int hashCode() {
return Objects.hash(id, name, code);
}
@Override
public String toString() {
return name;
}
@Override
public int compareTo(Country o) {
return name.compareTo(o.name);
}
}
package org.primefaces.showcase.service;
import org.primefaces.showcase.domain.Country;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Named;
@Named
@ApplicationScoped
public class CountryService {
private List<Country> countries;
private Map<Integer, Country> countriesAsMap;
private List<Country> locales;
private Map<Integer, Country> localesAsMap;
public static Stream<Country> toCountryStream(String... isoCodes) {
return Stream.of(isoCodes)
.map(isoCode -> new Locale.Builder().setRegion(isoCode).build())
.map(CountryService::toCountry);
}
private static Locale toLocale(String language, String country) {
return new Locale.Builder().setLanguage(language).setRegion(country).build();
}
public static Country toCountry(Locale locale) {
return CountryService.toCountry(locale, false);
}
public static Country toCountry(Locale locale, boolean rtl) {
//use hash code from locale to have a reproducible ID (required for CountryConverter)
return new Country(locale.hashCode(), locale, rtl);
}
@PostConstruct
public void init() {
countries = CountryService.toCountryStream(Locale.getISOCountries())
.sorted(Comparator.comparing(Country::getName))
.collect(Collectors.toList());
locales = new ArrayList<>();
locales.add(CountryService.toCountry(Locale.US));
locales.add(CountryService.toCountry(Locale.UK));
locales.add(CountryService.toCountry(toLocale("en", "AU")));
locales.add(CountryService.toCountry(Locale.FRANCE));
locales.add(CountryService.toCountry(Locale.GERMANY));
locales.add(CountryService.toCountry(toLocale("de", "AT")));
locales.add(CountryService.toCountry(toLocale("de", "CH")));
locales.add(CountryService.toCountry(Locale.ITALY));
locales.add(CountryService.toCountry(Locale.KOREA));
locales.add(CountryService.toCountry(toLocale("es", "ES")));
locales.add(CountryService.toCountry(toLocale("ca", "ES")));
locales.add(CountryService.toCountry(toLocale("nl", "NL")));
locales.add(CountryService.toCountry(toLocale("pt", "BR")));
locales.add(CountryService.toCountry(toLocale("pt", "PT")));
locales.add(CountryService.toCountry(toLocale("ar", "SA"), true));
locales.add(CountryService.toCountry(toLocale("ar", "TN"), true));
locales.add(CountryService.toCountry(toLocale("bg", "BG")));
locales.add(CountryService.toCountry(toLocale("bn", "BD")));
locales.add(CountryService.toCountry(toLocale("bs", "BA")));
locales.add(CountryService.toCountry(toLocale("cs", "CZ")));
locales.add(CountryService.toCountry(toLocale("el", "GR")));
locales.add(CountryService.toCountry(toLocale("et", "EE")));
locales.add(CountryService.toCountry(toLocale("fa", "IR"), true));
locales.add(CountryService.toCountry(toLocale("fi", "FI")));
locales.add(CountryService.toCountry(toLocale("da", "DK")));
locales.add(CountryService.toCountry(toLocale("hi", "IN")));
locales.add(CountryService.toCountry(toLocale("in", "ID")));
locales.add(CountryService.toCountry(toLocale("is", "IS")));
locales.add(CountryService.toCountry(toLocale("hr", "HR")));
locales.add(CountryService.toCountry(toLocale("ja", "JP")));
locales.add(CountryService.toCountry(toLocale("hu", "HU")));
locales.add(CountryService.toCountry(toLocale("he", "IL"), true));
locales.add(CountryService.toCountry(toLocale("ka", "GE")));
locales.add(CountryService.toCountry(toLocale("ckb", "IQ"), true));
locales.add(CountryService.toCountry(toLocale("km", "KH")));
locales.add(CountryService.toCountry(toLocale("ky", "KG")));
locales.add(CountryService.toCountry(toLocale("kk", "KZ")));
locales.add(CountryService.toCountry(toLocale("lt", "LT")));
locales.add(CountryService.toCountry(toLocale("lv", "LV")));
locales.add(CountryService.toCountry(toLocale("ms", "MY")));
locales.add(CountryService.toCountry(toLocale("no", "NO")));
locales.add(CountryService.toCountry(toLocale("pl", "PL")));
locales.add(CountryService.toCountry(toLocale("ro", "RO")));
locales.add(CountryService.toCountry(toLocale("ru", "RU")));
locales.add(CountryService.toCountry(toLocale("sk", "SK")));
locales.add(CountryService.toCountry(toLocale("sl", "SI")));
locales.add(CountryService.toCountry(toLocale("sr", "BA")));
locales.add(CountryService.toCountry(toLocale("sr", "RS")));
locales.add(CountryService.toCountry(toLocale("sv", "SE")));
locales.add(CountryService.toCountry(toLocale("th", "TH")));
locales.add(CountryService.toCountry(toLocale("tr", "TR")));
locales.add(CountryService.toCountry(toLocale("uk", "UA")));
locales.add(CountryService.toCountry(toLocale("uz", "UZ")));
locales.add(CountryService.toCountry(toLocale("vi", "VN")));
locales.add(CountryService.toCountry(Locale.SIMPLIFIED_CHINESE));
locales.add(CountryService.toCountry(Locale.TRADITIONAL_CHINESE));
}
public List<Country> getCountries() {
return new ArrayList<>(countries);
}
public Map<Integer, Country> getCountriesAsMap() {
if (countriesAsMap == null) {
countriesAsMap = getCountries().stream().collect(Collectors.toMap(Country::getId, country -> country));
}
return countriesAsMap;
}
public List<Country> getLocales() {
return new ArrayList<>(locales);
}
public Map<Integer, Country> getLocalesAsMap() {
if (localesAsMap == null) {
localesAsMap = getLocales().stream().collect(Collectors.toMap(Country::getId, country -> country));
}
return localesAsMap;
}
}
package org.primefaces.showcase.convert;
import org.primefaces.showcase.domain.Country;
import org.primefaces.showcase.service.CountryService;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.FacesContext;
import jakarta.faces.convert.Converter;
import jakarta.faces.convert.ConverterException;
import jakarta.faces.convert.FacesConverter;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@Named
@ApplicationScoped
@FacesConverter(value = "countryConverter", managed = true)
public class CountryConverter implements Converter<Country> {
@Inject
private CountryService countryService;
@Override
public Country getAsObject(FacesContext context, UIComponent component, String value) {
if (value != null && !value.trim().isEmpty()) {
try {
return countryService.getCountriesAsMap().get(Integer.parseInt(value));
}
catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Conversion Error", "Not a valid country."));
}
}
else {
return null;
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Country value) {
if (value != null) {
return String.valueOf(value.getId());
}
else {
return null;
}
}
}