AEM 6.5 trailing slash on void elements | Community
Skip to main content
Level 6
May 7, 2025
Solved

AEM 6.5 trailing slash on void elements

  • May 7, 2025
  • 1 reply
  • 1034 views

In my AEM 6.5 template, I have the following code snippet. When it gets rendered on the publish instance, the <br> tag is automatically converted to a self-closing <br/>tag, even though no self-closing tag is present in the original template. The same behavior occurs with the <meta...> tag, which is rendered as <meta..../> the same as other void elements. Could you help me understand why this happens? I’m asking because the W3C Validator flags this as an issue, stating: "Trailing slash on void elements has no effect and interacts badly with unquoted attribute values."

Here’s an example of the rendered output:
<head> <meta charset="UTF-8"/> </head>
Here is my AEM template snippet:

<li>
<sly data-sly-call="${iconTpl.icon @ icon='ui-checkmark', additionalClasses='c-icon--no-inline t-highlight t-highlight--positive'}"></sly>
<a target="_blank" rel="noreferrer" href="https://something" >Bonusprogram.</a>
tralalala<br>
</li>
This post is no longer active and is closed to new replies. Need help? Start a new post to ask your question.
Best answer by AmitVishwakarma

Hi @anasustic ,

This behavior you're seeing in AEM 6.5—where void elements like <br> and <meta> are rendered with a trailing slash (<br/>, <meta/>)—is due to the XML-style serialization done by HTL (Sightly) or the underlying Sling engine, which defaults to XHTML output mode in many scenarios.

Why this happens

HTL (HTML Template Language) in AEM doesn't render templates as plain HTML. Instead, it uses XML serialization rules from the underlying parsers (like Xerces or SAX). According to XHTML standards, void elements like <br>, <meta>, <img> are self-closing, hence it outputs them as <br/>, <meta/>, etc.

This is compliant with XHTML, but not strictly HTML5, which is what the W3C validator is flagging.

W3C Validator Warning

The W3C HTML validator warns:

“Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.”

That’s because in HTML5, void elements must not be self-closed (e.g., <br> is correct, but <br/> is discouraged though still technically allowed in most browsers).

1 reply

AmitVishwakarma
Community Advisor
AmitVishwakarmaCommunity AdvisorAccepted solution
Community Advisor
May 7, 2025

Hi @anasustic ,

This behavior you're seeing in AEM 6.5—where void elements like <br> and <meta> are rendered with a trailing slash (<br/>, <meta/>)—is due to the XML-style serialization done by HTL (Sightly) or the underlying Sling engine, which defaults to XHTML output mode in many scenarios.

Why this happens

HTL (HTML Template Language) in AEM doesn't render templates as plain HTML. Instead, it uses XML serialization rules from the underlying parsers (like Xerces or SAX). According to XHTML standards, void elements like <br>, <meta>, <img> are self-closing, hence it outputs them as <br/>, <meta/>, etc.

This is compliant with XHTML, but not strictly HTML5, which is what the W3C validator is flagging.

W3C Validator Warning

The W3C HTML validator warns:

“Trailing slash on void elements has no effect and interacts badly with unquoted attribute values.”

That’s because in HTML5, void elements must not be self-closed (e.g., <br> is correct, but <br/> is discouraged though still technically allowed in most browsers).

anasusticAuthor
Level 6
May 7, 2025

Thanks so much for your detailed answer.
@amitvishwakarma can you please suggest how would you go about customizing the response (your suggested option 1)

 

AmitVishwakarma
Community Advisor
Community Advisor
May 7, 2025

Hi @anasustic ,

Using a Servlet Filter that intercepts the response and modifies the serialized output before it’s sent to the client.

Servlet Filter to Post-process Output

1. Create the Servlet Filter

Create a filter that wraps the response and modifies the output stream to replace XHTML-style void elements (<br/>, <meta/>) with their HTML5 equivalents (<br>, <meta>).

package com.example.core.filters; import org.apache.commons.io.output.TeeOutputStream; import org.osgi.service.component.annotations.Component; import org.osgi.framework.Constants; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletResponse; import java.io.*; @Component(service = Filter.class, property = { Constants.SERVICE_RANKING + ":Integer=100", "sling.filter.scope=REQUEST" }) public class HtmlVoidElementFixFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { CharResponseWrapper responseWrapper = new CharResponseWrapper((HttpServletResponse) response); chain.doFilter(request, responseWrapper); String originalContent = responseWrapper.toString(); // Replace self-closing void elements with HTML5-compliant ones String updatedContent = originalContent .replaceAll("<br\\s*/>", "<br>") .replaceAll("<meta([^>]*)\\s*/>", "<meta$1>"); response.getWriter().write(updatedContent); } }

2. Create the CharResponseWrapper

This wrapper captures the output of the servlet before it's sent to the browser.

import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; import java.io.CharArrayWriter; import java.io.PrintWriter; public class CharResponseWrapper extends HttpServletResponseWrapper { private final CharArrayWriter output; public CharResponseWrapper(HttpServletResponse response) { super(response); output = new CharArrayWriter(); } @Override public PrintWriter getWriter() { return new PrintWriter(output); } @Override public String toString() { return output.toString(); } }

What This Does

 - Intercepts the HTML output

 - Rewrites self-closed tags like <br/> or <meta .../> into <br> and <meta ...>

 - Keeps the rest of the response untouched

Note:

 - This works only for text/html responses (which most AEM pages are).

 - Be careful not to overmatch or accidentally rewrite self-closing tags inside <script> or <style>.


Regards,
Amit