The solution that I found was to extend and re-implement the encodeMarkup methods for the input renderers. I wanted a more general solution, but after looking at the Primefaces source code, I did not see any generic hooks for the component renderers to add custom attributes. The markup is written out in the encodeMarkup(FacesContext context, InputText inputText)
methods of the renderers. It calls up the class-hierarchy to renderPassThruAttributes(FacesContext context, UIComponent component, String[] attributes)
but it only feeds in static final String[] arrays from org.primefaces.util.HTML
.
In my case I wanted support for the 'autofocus' attribute on InputMask, InputText, InputTextarea, and Password components. Furthermore, the implementation is the same for each component, so I will walk through implementing 'autofocus' on the InputText component, but it should be obvious how it can be extended to support more attributes and more components.
To extend/override a renderer, you will need to have the Primefaces source available and find the encodeMarkup method and copy its contents. Here is the example for InputTextRenderer:
protected void encodeMarkup(FacesContext context, InputText inputText) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = inputText.getClientId(context);
writer.startElement("input", null);
writer.writeAttribute("id", clientId, null);
writer.writeAttribute("name", clientId, null);
writer.writeAttribute("type", inputText.getType(), null);
String valueToRender = ComponentUtils.getValueToRender(context, inputText);
if(valueToRender != null) {
writer.writeAttribute("value", valueToRender , null);
}
renderPassThruAttributes(context, inputText, HTML.INPUT_TEXT_ATTRS);
if(inputText.isDisabled()) writer.writeAttribute("disabled", "disabled", null);
if(inputText.isReadonly()) writer.writeAttribute("readonly", "readonly", null);
if(inputText.getStyle() != null) writer.writeAttribute("style", inputText.getStyle(), null);
writer.writeAttribute("class", createStyleClass(inputText), "styleClass");
writer.endElement("input");
}
Extending/Overriding the renderer with your own (see comments for important code):
public class HTML5InputTextRenderer extends InputTextRenderer {
Logger log = Logger.getLogger(HTML5InputTextRenderer.class);
//Define your attributes to support here
private static final String[] html5_attributes = { "autofocus" };
protected void encodeMarkup(FacesContext context, InputText inputText) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = inputText.getClientId(context);
writer.startElement("input", null);
writer.writeAttribute("id", clientId, null);
writer.writeAttribute("name", clientId, null);
writer.writeAttribute("type", inputText.getType(), null);
String valueToRender = ComponentUtils.getValueToRender(context, inputText);
if (valueToRender != null) {
writer.writeAttribute("value", valueToRender, null);
}
renderPassThruAttributes(context, inputText, HTML.INPUT_TEXT_ATTRS);
//Make an extra call to renderPassThruAttributes with your own attributes array
renderPassThruAttributes(context, inputText, html5_attributes);
if (inputText.isDisabled())
writer.writeAttribute("disabled", "disabled", null);
if (inputText.isReadonly())
writer.writeAttribute("readonly", "readonly", null);
if (inputText.getStyle() != null)
writer.writeAttribute("style", inputText.getStyle(), null);
writer.writeAttribute("class", createStyleClass(inputText), "styleClass");
writer.endElement("input");
}
}
Configuring the rendering override in faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
version="2.0">
<!-- snip... -->
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.InputTextRenderer</renderer-type>
<renderer-class>com.mycompany.HTML5InputTextRenderer</renderer-class>
</renderer>
</render-kit>
<!-- snip... -->
</faces-config>
and just-in-case if you didn't have the faces-config configured in your web.xml add:
<context-param>
<param-name>javax.faces.CONFIG_FILES</param-name>
<param-value>
/WEB-INF/faces-config.xml, /faces-config.xml
</param-value>
</context-param>
Then to use this in some markup:
<p:inputText id="activateUserName" value="${someBean.userName}"
autofocus="on">
</p:inputText>
Note: JSF is not happy with attributes that do not have values. While autofocus in HTML5 does not use a value, JSF will throw an error if one is not given, so make sure to define some throw-away value when adding such attributes.