By Default, Jsf Generates Unusable Ids, Which Are Incompatible with the CSS Part of Web Standards

By default, JSF generates unusable IDs, which are incompatible with the CSS part of web standards

The : is been chosen because that's the only sensible separator character for which can be guaranteed that the enduser won't accidently use it in JSF component IDs (which is been validated) and that it's possible to use it in CSS selectors by escaping it with \.

Note that the HTML4 spec says that the colon is a valid value in id and name attribute. So your complaint that it isn't compatible with "web standards" goes nowhere.

ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").

The only problem is thus that the : is a special character in CSS selectors which needs to be escaped. JS has at its own no problems with colons. The document.getElementById("foo:bar") works perfectly fine. The only possible problem is in jQuery because it uses CSS selector syntax.

If you really need to, then you can always change the default separator character : by setting the javax.faces.SEPARATOR_CHAR context param to e.g. - or _ as below. You only need to guarantee that you don't use that character anywhere in JSF component IDs yourself (it's not been validated!).

<context-param>
<param-name>javax.faces.SEPARATOR_CHAR</param-name>
<param-value>-</param-value>
</context-param>

The _ has by the way the additional disadvantage that it occurs in JSF autogenerated IDs like j_id1, thus you should also ensure that all NamingContainer components throughout your JSF pages have a fixed ID instead of an autogenerated one. Otherwise JSF will have problems finding naming container children.

I would only not recommend it. It's in long term confusing and brittle. To think about it again, unique elements in the average JSF webapp are by itself usually already not inside forms or tables. They generally just represent the main layout aspects. I'd say, it's otherwise a bad design in general HTML/CSS perspective. Just select them by reusable CSS class names instead of IDs. If you really need to, you can always wrap it in a plain HTML <div> or <span> whose ID won't be prepended by JSF.

See also:

  • What are valid values for the id attribute in HTML?
  • Is it possible to change the element id separator in JSF?
  • How to select JSF components using jQuery?
  • How to use JSF generated HTML element ID with colon ":" in CSS selectors?
  • Integrate JavaScript in JSF composite component, the clean way

The CSS selector for an element that its id is in the foo:bar form

According to the W3c spec linked to in this answer, using colons in element IDs is plain wrong if used unescaped.

In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-z0-9] and ISO 10646 characters U+00A1 and higher, plus the hyphen (-) and the underscore (_); they cannot start with a digit, or a hyphen followed by a digit. Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F".

Is the JSF framework really outputting those IDs in the final rendered HTML?

Is there a common replacement for javax.faces.SEPARATOR_CHAR?

I don't like how JSF uses the colon to separate ID's in generated HTML, as it collides with CSS and JavaScript Selectors. And I don't like the idea of always escaping it.

Just select elements by classname then? Is the HTML element's nature really so unique that it requires being selected by an ID? This is usually only the case for main layout components.


Thus I would like to replace it by some other character. Are there any drawbacks? And is there a common replacement?

You can use any character you want, provided that it's valid in HTML element ID/name which is specified as follows:

ID and NAME tokens must begin with a letter ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"), colons (":"), and periods (".").

Next to the colon, the only sensible choices are the hyphen, the underscore and the period. As the period is at its own also a special character in CSS selectors, it would have the same problem as the colon. So logically you don't have much other choice than the hyphen - and the underscore _.

As to the drawbacks, certainly there are drawbacks. You need to ensure that you are not using the new separator character anywhere in JSF component IDs like so <h:someComponent id="foo_bar" /> in case of _. Those characters are namely allowed in JSF component IDs (the colon isn't). It would break the UIComponent#findComponent() lookup.

See also:

  • By default, JSF generates unusable ids, which are incompatible with css part of web standards

How to use JSF generated HTML element ID with colon : in CSS selectors?

The : is a special character in CSS identifiers, it represents the start of a pseudo class selector like :hover, :first-child, etc. You would need to escape it.

#phoneForm\:phoneTable {
background: pink;
}

This only doesn't work in IE6/7. If you'd like to support those users as well, use \3A instead (with a trailing space behind!)

#phoneForm\3A phoneTable {
background: pink;
}

Above works in all browsers.


There are several other ways to solve this:

  1. Just wrap it in a plain HTML element and style via it instead.

     <h:form id="phoneForm">
    <div id="phoneField">
    <h:dataTable id="phoneTable">

    with

     #phoneField table {
    background: pink;
    }


  2. Use class instead of id. E.g.

     <h:dataTable id="phoneTable" styleClass="pink">

    with

     .pink {
    background: pink;
    }

    or

     table.pink {
    background: pink;
    }

    Additional advantage is that this allows much more abstraction freedom. The CSS is reusable on multiple elements without the need to add selectors and/or copypaste properties when you want to reuse the same properties on another element(s).



  3. Since JSF 2.x only: change the JSF default UINamingContainer separator by the following context param in web.xml. E.g.

     <context-param>
    <param-name>javax.faces.SEPARATOR_CHAR</param-name>
    <param-value>-</param-value>
    </context-param>

    So that the separator character becomes - instead of :.

     #phoneForm-phoneTable {
    background: pink;
    }

    Disadvantage is that you need to ensure that you don't use this character yourself anywhere in the ids and this is thus a very brittle approach. I do not recommend this approach. This is a bad practice.



  4. Since JSF 1.2 only: disable prepending of the form id.

     <h:form prependId="false">
    <h:dataTable id="phoneTable">

    so that you can use

     #phoneTable {
    background: pink;
    }

    Disadvantage is that <f:ajax> won't be able to find it and that it is considered poor practice: UIForm with prependId="false" breaks <f:ajax render>. I do not recommend this approach. This is a bad practice. Moreover, this attribute does not exist in all other UINamingContainer components, so you still have to deal with them the right way (#1 and/or #2 here above).



In your specific case, I think turning it into a CSS class as described in #2 is the most appropriate solution. A "phone table" namely doesn't seem to represent a website-wide unique element. Real website-wide unique elements such as header, menu, content, footer, etc are usually not wrapped in JSF forms or other JSF naming containers, so their IDs wouldn't be prefixed anyway.

See also:

  • How to select JSF components using jQuery?
  • By default, JSF generates unusable IDs, which are incompatible with the CSS part of web standards

Disabling input fields in a form using jQuery

While valid in HTML element IDs/names, the colon is a special character in CSS selectors as it represents the start of pseudo selector. You need to escape it in CSS selectors.

jQuery('form#_jpfcpncuivr_A2262_j_id1\\:fundRequestForm input[type!="hidden"]').attr('disabled', 'true');

See also:

  • How to select JSF components using jQuery? (for a more detailed answer with alternatives)
  • By default, JSF generates unusable ids, which are incompatible with css part of web standards (someone else ranted that it was standards-incompatible, but the answer proved it wrong)

Is it possible to use JSF to build clean CSS layouts without using tables?

the liberal use of html tables for layout by many components

Many components? There are as far as I know only two which do that "unnecessarily": the <h:selectOneRadio> and <h:selectManyCheckbox>. If you want a table-less group of radiobuttons and checkboxes wherein you have the full control over the generated markup, just use the Tomahawk variant instead, which has an extra layout attribute value of spread. Here's an example of the <t:selectOneRadio> approach:

<t:selectOneRadio id="foo" value="#{bean.foo}" layout="spread">
<f:selectItems value="#{bean.foos}" />
</t:selectOneRadio>
...
<t:radio for="foo" index="0" />
...
<t:radio for="foo" index="1" />
...
<t:radio for="foo" index="2" />
...

Since JSF 2.2 it's even possible to do it "out the box" with new passthrough elements/attributes feature. Since JSF 2.3 it has even become part of standard component set. See also a.o. <h:selectOneRadio> renders table element, how to avoid this?

For the remainder, you just have the control of the general HTML output fully in your own hands. Just do not use tables for layout at all. I.e. do not use HTML <table> or JSF <h:panelGrid> for layout. Just use HTML <div> elements to display content blocks. Or if you're a JSF-purist, you can use <h:panelGroup layout="block"> to let JSF generate a HTML <div> element.

As to applying CSS, it isn't that hard, every JSF HTML component has a styleClass attribute wherein you can specify CSS classes (which would end up in a HTML class attribute) and style attribute wherein you can specify inline CSS (which would end up in a HTML style attribute).

You can even define global CSS styles and use the ID selectors. Only thing which you need to take care in JSF+CSS is that the JSF-generated HTML element IDs are prepended with the IDs of all parent NamingContainer components (e.g. <h:form>, <h:dataTable>, etc) with a colon : as separator. As the colon is an illegal character in CSS identifiers, you need to escape it using \. So styling the input element of for example

<h:form id="form">
<h:inputText id="input" ... />

which generates <input type="text" id="form:input" ... /> should be done as

#form\:input {
background: gray;
}

It's however very rare to select form input elements or table elements by ID. More commonly the classname is to be used (which is more semantic and better reuseable) and this doesn't need to be escaped. The ID are usually used by main layout components only anyway (header, menu, content, footer, title, etc) and they usually don't end up in a JSF NamingContainer.

See also:

  • How to use JSF generated HTML element ID with colon ":" in CSS selectors?
  • By default, JSF generates unusable ids, which are incompatible with css part of web standards
  • What is the need of JSF, when UI can be achieved from CSS, HTML, JavaScript, jQuery?
  • JavaServer Faces 2.2 and HTML5 support, why is XHTML still being used

I seem to be labouring under a misaprehension here, but every JSF tutorial I've seen ends up producing table-based HTML layouts. I've also looked at RichFaces and IceFaces demos and there's an awful lot of tables-for-layout there as well.

Start here: Java EE web development, where do I start and what skills do I need?

Is it possible to change the element id separator in JSF?

This is not possible in JSF 1.x, but since JSF 2.x you can define it in web.xml as init-param of javax.faces.SEPARATOR_CHAR.

That said, I guess that you just wanted to change it because you'd like to get your CSS to work, is it? The colon : is namely a special character in CSS identifiers, it represents a pseudo selector. If this reason is true for you, then it might be good to know that you can escape special characters in CSS the usual way by \.

Thus, e.g.

#levelone\:leveltwo {
color: blue;
}

ought to work for normal browsers (for IE6/7 you need #levelone\3A leveltwo instead).

The same applies when you intend to use it with jQuery or any other JavaScript framework which selects elements with help of CSS selectors:

var leveltwo = $('#levelone\\:leveltwo');


Alternatively, you can also just give it a styleClass which you in turn can correlate with a CSS class. Thus, e.g.

<h:inputText styleClass="myinput" />

which generates

<input type="text" class="myinput" />

can be styled with

.myinput {
color: blue;
}

See also

  • How to select JSF components using jQuery?
  • How to use JSF generated HTML element ID with colon ":" in CSS selectors?

UIForm with prependId= false breaks f:ajax render

Indeed, UIComponent#findComponent() as done by <f:ajax render> fails when using <h:form prependId="false">. This problem is known and is a "Won't fix": JSF spec issue 573.

In my humble opinion, they should never have added the prependId attribute to the UIForm during the JSF 1.2 ages. It was merely done to keep j_security_check users happy who would like to use a JSF form with JSF input components for that (j_security_check requires exact input field names j_username and j_password which couldn't be modified by configuration). But they didn't exactly realize that during JSF 1.2 another improvement was introduced which enables you to just keep using <form> for that instead of sticking to <h:form>. And then CSS/jQuery purists start abusing prependId="false" to avoid escaping the separator character : in their poorly chosen CSS selectors.

Just don't use prependId="false", ever.

For j_security_check, just use <form> or the new Servlet 3.0 HttpServletRequest#login(). See also Performing user authentication in Java EE / JSF using j_security_check.

For CSS selectors, in case you absolutely need an ID selector (and thus not a more reusable class selector), simply wrap the component of interest in a plain HTML <div> or <span>.

See also:

  • How to select JSF components using jQuery?
  • How to use JSF generated HTML element ID with colon ":" in CSS selectors?
  • By default, JSF generates unusable ids, which are incompatible with css part of web standards

When and how is clientID generated in JSF?

In order to more understand the clientID generation in JSF (2.x), could someone explain to me when exactely does JSF generates the client ID (which lifecycle phase, build time or render time ...)?

It has to end up in HTML response. It's thus generated during render response. If you put a debug breakpoint on UIComponent#getClientId() method, then you'll see further down in the stack that (in case of Mojarra) RenderResponsePhase#execute() has been invoked. This is sufficient hint about the current phase in the lifecycle when the breakpoint is hit.

And how the client ID will be generated (if providing /not providing component ID and not, randomly or using a specific logic...)?

The concrete implementation of the abstract UIComponent#getClientId() method can be found in UIComponentBase#getClientId(). Its source code can be found at grepcode. How it will be generated is just described in its javadoc:

public abstract String getClientId(FacesContext context)

Return a client-side identifier for this component, generating one if necessary. The associated Renderer, if any, will be asked to convert the clientId to a form suitable for transmission to the client.

The return from this method must be the same value throughout the lifetime of the instance, unless the id property of the component is changed, or the component is placed in a NamingContainer whose client ID changes (for example, UIData). However, even in these cases, consecutive calls to this method must always return the same value. The implementation must follow these steps in determining the clientId:

Find the closest ancestor to this component in the view hierarchy that implements NamingContainer. Call getContainerClientId() on it and save the result as the parentId local variable. Call getId() on this component and save the result as the myId local variable. If myId is null, call context.getViewRoot().createUniqueId() and assign the result to myId. If parentId is non-null, let myId equal parentId +UINamingContainer.getSeparatorChar(javax.faces.context.FacesContext)+ myId. Call Renderer.convertClientId(javax.faces.context.FacesContext, java.lang.String), passing myId, and return the result.

Pretty clear, is it? The most important part is perhaps memorizing components which implement NamingContainer and thus prepend their client ID. In standard JSF 2.x, that are at least <h:form>, <h:dataTable>, <ui:repeat>, <f:subview> and <cc:implementation>. If you gently give all components a fixed ID, then you'll also see that pattern back in the generated HTML output.

If you don't give those components a fixed ID, then instead the JSF-generated ID will be used which can be obtained via UIViewRoot#createUniqueId() (as already hinted in the above javadoc extract). Its javadoc says:

public String createUniqueId()

Generate an identifier for a component. The identifier will be prefixed with UNIQUE_ID_PREFIX, and will be unique within the non-NamingContainer child sub-trees of this UIViewRoot.

That prefix is j_id. It isn't explicit on how the implementation should generate it, so all implementors are free to implement it. They usually use an incremented index of the component count in the tree. So, the first component, the UIViewRoot, could get an ID of j_id1. Its first child could get an ID of j_id2. Etcetera. You can track back the logic by putting a debug breakpoint on UIViewRoot#createUniqueId() method or even the UIComponentBase#setId() method.

See also:

  • How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
  • By default, JSF generates unusable ids, which are incompatible with css part of web standards
  • Avoiding duplicate ids when reusing facelets compositions in the same naming container


Related Topics



Leave a reply



Submit