PrimeFaces SelectOneButton and SelectManyButton Custom Rendering
— PrimeFaces, JSF, Faces — 5 min read
PrimeFaces 15.0.10 introduces a significant enhancement to the SelectOneButton and SelectManyButton components: support for custom rendering. This new feature enables developers to completely customize the appearance and content of button options, including the ability to add badges, icons, and other custom elements, providing greater flexibility in designing user interfaces.
What Is Custom Rendering?
Custom rendering allows you to define custom HTML structure for each button option using the custom facet. Instead of being limited to simple text labels, you can now create fully customized button layouts with any HTML elements, JSF components, or PrimeFaces components like badges. This feature provides complete control over how each option is displayed.
Custom Layout Using Facet
The most straightforward approach is to use the custom facet directly within the component. You define one custom button element for each f:selectItem, and each custom button must have role="radio" and tabindex attributes for proper accessibility and functionality.
Here's an example that demonstrates custom rendering with color indicators and badges:
1<p:selectOneButton id="customButton" value="#{selectOneButtonView.color}">2 <p:ajax event="change" listener="#{selectOneButtonView.onChange}" />3 4 <f:selectItem itemLabel="Red" itemValue="Red"/>5 <f:selectItem itemLabel="Green" itemValue="Green"/>6 <f:selectItem itemLabel="Blue" itemValue="Blue"/>7
8 <f:facet name="custom">9 <div class="custom-button" role="radio" tabindex="0">10 <span class="legend" style="background:red; display:inline-block; width:1rem; height:1rem; border-radius:0.25rem; vertical-align:middle; margin-right:0.5rem;"/> Red11 </div>12 <div class="custom-button" role="radio" tabindex="0">13 <span class="legend" style="background:green; display:inline-block; width:1rem; height:1rem; border-radius:0.25rem; vertical-align:middle; margin-right:0.5rem;"/> Green14 </div>15 <p:badge icon="pi pi-bell" severity="info" iconPos="left">16 <div class="custom-button" role="radio" tabindex="0">17 <span class="legend" style="background:blue; display:inline-block; width:1rem; height:1rem; border-radius:0.25rem; vertical-align:middle; margin-right:0.5rem;"/> Blue18 </div>19 </p:badge>20 </f:facet>21</p:selectOneButton>In this example, each button option displays a colored legend indicator along with its label. The third option (Blue) is wrapped in a p:badge component to demonstrate how badges can be integrated with custom rendering.
Custom Layout Using Referenced Elements
For more complex layouts or when you need to separate the button definitions from the component, you can use the layout="custom" attribute and define the custom buttons outside the component. The buttons are matched to the f:selectItem elements by their order.
Here's an example demonstrating a payment method selector with icons and detailed information:
1<div id="customButton2Container">2 <p:selectOneButton id="customButton2" value="#{selectOneButtonView.paymentMethod}" layout="custom">3 <p:ajax event="change" listener="#{selectOneButtonView.onChange}" />4
5 <f:selectItem itemLabel="PayPal" itemValue="PayPal"/>6 <f:selectItem itemLabel="Bitcoin" itemValue="Bitcoin"/>7 <f:selectItem itemLabel="Credit Card" itemValue="Credit Card" itemDisabled="true"/>8 <f:selectItem itemLabel="Cash" itemValue="Cash"/>9 </p:selectOneButton>10
11 <div class="flex flex-wrap justify-content-start mt-3">12 <div class="payment-button paypal" role="radio" tabindex="0">13 <i class="pi pi-paypal payment-icon"></i>14 <div class="payment-title">PayPal</div>15 <div class="payment-tagline">Secure online payment</div>16 </div>17 <div class="payment-button bitcoin" role="radio" tabindex="0">18 <i class="pi pi-bitcoin payment-icon"></i>19 <div class="payment-title">Bitcoin</div>20 <div class="payment-tagline">Cryptocurrency payment</div>21 </div>22 <div class="payment-button creditcard ui-state-disabled" role="radio" tabindex="-1">23 <i class="pi pi-credit-card payment-icon"></i>24 <div class="payment-title">Credit Card</div>25 <div class="payment-tagline">Currently unavailable</div>26 </div>27 <div class="payment-button cash" role="radio" tabindex="0">28 <i class="pi pi-money-bill payment-icon"></i>29 <div class="payment-title">Cash</div>30 <div class="payment-tagline">Pay on delivery</div>31 </div>32 </div>33</div>This approach allows for more complex layouts with multiple elements per button, such as icons, titles, and taglines. Note that disabled items should have tabindex="-1" and the ui-state-disabled class.
Key Requirements for Custom Rendering
When implementing custom rendering, keep these requirements in mind:
-
One custom button per selectItem: Each
f:selectItemmust have a corresponding custom button element in thecustomfacet or in the referenced container. -
Required attributes: Each custom button must have:
role="radio"for accessibilitytabindex="0"for enabled items (ortabindex="-1"for disabled items)
-
Order matters: The order of custom buttons must match the order of
f:selectItemelements. -
Badge integration: Badges can wrap custom button elements or be included within them, as shown in the first example.
SelectManyButton with Custom Rendering
The SelectManyButton component supports the same custom rendering features. You can use either the custom facet or the layout="custom" approach:
1<p:selectManyButton value="#{bean.selectedOptions}">2 <f:selectItem itemLabel="Option A" itemValue="A" />3 <f:selectItem itemLabel="Option B" itemValue="B" />4 <f:selectItem itemLabel="Option C" itemValue="C" />5 6 <f:facet name="custom">7 <div class="custom-button" role="checkbox" tabindex="0">8 <p:badge value="3" severity="success" />9 <span>Option A</span>10 </div>11 <div class="custom-button" role="checkbox" tabindex="0">12 <p:badge value="5" severity="warning" />13 <span>Option B</span>14 </div>15 <div class="custom-button" role="checkbox" tabindex="0">16 <span>Option C</span>17 </div>18 </f:facet>19</p:selectManyButton>Note that for SelectManyButton, the role should be "checkbox" instead of "radio".
Backing Bean Example
Here's a simple backing bean that can support custom rendering:
1@Named2@ViewScoped3public class SelectOneButtonView implements Serializable {4 private String color;5 private String paymentMethod;6
7 public void onChange(AjaxBehaviorEvent event) {8 // Handle the change event9 // You can access the component and perform any necessary logic10 }11
12 // Getters and setters13 public String getColor() {14 return color;15 }16
17 public void setColor(String color) {18 this.color = color;19 }20
21 public String getPaymentMethod() {22 return paymentMethod;23 }24
25 public void setPaymentMethod(String paymentMethod) {26 this.paymentMethod = paymentMethod;27 }28}Benefits
The addition of custom rendering to SelectOneButton and SelectManyButton provides several advantages:
- Complete Design Control: Create fully customized button layouts that match your application's design requirements and branding.
- Badge Support: Adding badges to buttons, a frequently requested feature, is now possible through custom rendering. Display counts, status indicators, or any other contextual information.
- Rich Content: Include icons, images, multiple text elements, or any other HTML/JSF components within button options.
- Improved User Experience: Provide users with more context and visual cues directly within the button options, making interfaces more intuitive and engaging.
- Flexible Layouts: Choose between inline facet-based rendering or referenced external layouts depending on your needs.
Conclusion
The custom rendering feature in PrimeFaces 15.0.10 makes SelectOneButton and SelectManyButton more powerful and flexible components. By leveraging the custom facet or layout="custom" attribute, developers can create visually rich and informative user interfaces that go far beyond simple text labels. Whether you need to add badges, icons, complex layouts, or other custom content, custom rendering provides the flexibility to tailor these components to your specific needs.
For more detailed information and additional configuration options, refer to the official PrimeFaces documentation: