Clarify/align `h:panelGroup` rendering: `layout`, the wrapper-element optimization, and the conflicting docs
- Dominant language
- Java
- Stars
- 127
- Forks
- 59
- Avg merge
- 23h
- Merged PRs (30d)
- 7
Description
### Summary
The documented rendering contract for `h:panelGroup` (renderer `jakarta.faces.Group`) is inconsistent across the four normative sources, and none of them describes what Mojarra and MyFaces actually do. In particular:
1. The `layout` property is documented as **unconditionally** producing a `div` for `layout="block"`, but neither implementation does that.
2. Both implementations only render a wrapper element (`div`/`span`) at all when the component carries something worth hanging on it (id / style / styleClass / …). This long-standing optimization is **undocumented**.
3. The renderkitdoc's own description of the renderer disagrees with the `layout` property description.
### The four sources, verbatim
**1. `layout` property javadoc** — `HtmlPanelGroup.getLayout()` ([apidocs](https://jakarta.ee/specifications/faces/4.1/apidocs/jakarta.faces/jakarta/faces/component/html/htmlpanelgroup)):
> The type of layout markup to use when rendering this group. If the value is "block" the renderer must produce an HTML "div" element. Otherwise HTML "span" element must be produced.
**2. vdldoc / taglib** — `faces.html.taglib.xml`, `panelGroup` / `layout` attribute ([vdldoc](https://jakarta.ee/specifications/faces/4.1/vdldoc/h/panelgroup), identical wording):
> The type of layout markup to use when rendering this group. If the value is "block" the renderer must produce an HTML "div" element. Otherwise HTML "span" element must be produced.
**3. renderkitdoc** — `standard-html-renderkit.xml`, the `jakarta.faces.Group` renderer description ([renderkitdoc](https://jakarta.ee/specifications/faces/4.1/renderkitdoc/html_basic/jakarta.faces.paneljakarta.faces.group)):
> Intended for use in situations when only one UIComponent child can be nested, such as in the case of facets. If the "style" or "styleClass" attributes are present, **and** the "layout" attribute is present with a value of "block", render a "div" element [...]. Otherwise, if the "layout" attribute is not present, or the "layout" attribute contains a value other than "block", render a "span" element [...].
The same file's `layout` *attribute* description, however, repeats source 1's unconditional wording.
**4. Actual implementations** — a wrapper is rendered only when there is something to put on it; `layout` only selects `div` vs `span` *once that decision is already made*.
- Mojarra (`GroupRenderer.divOrSpan`): wrapper iff `shouldWriteIdAttribute(component) || style != null || styleClass != null`.
- MyFaces (`HtmlGroupRendererBase.encodeEnd`): wrapper iff `shouldRenderId(...) || !behaviors.isEmpty() ||` any passthrough/universal attribute is present.
This behavior is original, not a regression — Mojarra has gated the wrapper since the JSF 1.0 sources (then named `spanned()`); the `div`/`layout` branch was layered on top in 2.0 inside the same gate.
### The contradictions
- **javadoc/vdldoc vs reality:** `` with no other attributes renders **nothing** in both impls — not the `div` the property docs say "must" be produced.
- **javadoc/vdldoc vs renderkitdoc:** the property docs make `block ⟹ div` unconditional; the renderkitdoc requires `style`/`styleClass` to *also* be present, and would route bare `layout="block"` into the "otherwise → span" branch.
- **All docs vs reality:** none of the four documents the wrapper-omission optimization, the `id` trigger, or (for MyFaces) the behavior/passthrough triggers.
### Proposed resolution
Two options; they are not mutually exclusive.
**(a) Make `layout` an explicit trigger (preferred; behavior change, needs EG decision + spec version gate).** Treat an explicitly specified `layout` as author intent to emit the box, so `` always renders an (possibly empty) `div`. This matches the literal javadoc and serves real use cases (CSS child/descendant selectors, flex/grid slots, JS hooks). Because both impls currently omit the element here, this would change rendered output for existing pages and should be tied to a spec revision.
**(b) Document the existing behavior for the remaining cases (doc-only, no behavior change).** Independently of (a), the docs must describe when a wrapper is emitted absent an explicit `layout`. Favor the broader MyFaces gate as the specified minimum — i.e. render the wrapper for **any renderable attribute**, not just `style`/`styleClass`:
> A wrapper element is rendered when the component has a renderable client id, or any renderable attribute is present (`style`, `styleClass`, any passthrough attribute, or an attached client behavior). When a wrapper element is rendered, a value of "block" for the `layout` attribute produces a `div`; any other value (or an absent `layout`) produces a `span`.
This makes the docs truthful immediately and can ship without affecting output. The current Mojarra gate (`id`/`style`/`styleClass` only) would be tightened toward this MyFaces-style "any renderable attribute" wording.
Recommendation: pursue (a) as the target end state in a spec revision; adopt (b)'s wording now to stop the docs being wrong and to standardize the no-`layout` behavior on the MyFaces approach.
### References
Specification docs (Faces 4.1):
- apidocs — [`HtmlPanelGroup`](https://jakarta.ee/specifications/faces/4.1/apidocs/jakarta.faces/jakarta/faces/component/html/htmlpanelgroup)
- vdldoc — [`h:panelGroup`](https://jakarta.ee/specifications/faces/4.1/vdldoc/h/panelgroup)
- renderkitdoc — [`jakarta.faces.Panel` / `jakarta.faces.Group`](https://jakarta.ee/specifications/faces/4.1/renderkitdoc/html_basic/jakarta.faces.paneljakarta.faces.group)
Implementations:
- Mojarra — [`GroupRenderer`](https://github.com/eclipse-ee4j/mojarra/blob/master/impl/src/main/java/com/sun/faces/renderkit/html_basic/GroupRenderer.java) (`divOrSpan` / `encodeBegin`)
- MyFaces — [`HtmlGroupRendererBase`](https://github.com/apache/myfaces/blob/main/impl/src/main/java/org/apache/myfaces/renderkit/html/base/HtmlGroupRendererBase.java) (`encodeEnd`)
Contributor guide
Research direction
Compare the four normative sources with Mojarra's GroupRenderer.java (especially divOrSpan/encodeBegin) and MyFaces' HtmlGroupRendererBase.java (encodeEnd). First establish the EG decision on explicit layout and the wrapper-emission rule; done means the API javadoc, vdldoc, and renderkitdoc agree with the selected behavior and its spec-version scope.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100