Table of contents
12 Embedding / Inlining
12.1 Embedding / Expression inlining Expressions
Although the standard dialect allows us to do almost everything using tag attributes, there are situations where we may prefer to write expressions directly in our HTML texts. For example, we might prefer to write this:
<p>Hello, [[${session.user.name}]]!</p>
… instead of this:
<p>Hello, <span th:text="${session.user.name}">Sebastian</span>!</p>
Expressions between
[[...]] or
[(...)] are considered to be inline expressions, and inside them we can use any expression that would also be valid in the
th: text or
th: utext attribute .
')
Note that although
[[...]] matches
th: text (i.e. the result will be with HTML escaped / HTML-escaped),
[(...)] matches
th: utext and will not perform HTML escaping / Html escaping. So with a variable such as msg = 'This is <b> great! </ B>', given this snippet:
The message is "[($ {msg})]"
As a result, <b> tags will not be escaped, so the result is:
<p>The message is "This is <b>great!</b>"</p>
To avoid this:
<p>The message is "[[${msg}]]"</p>
The result will be HTML shielded:
<p>The message is "This is <b>great!</b>"</p>
Please note that the default text insert is active in the body of each tag in our markup - not the tags themselves, so we have nothing to do to turn it on (make it active).
Inset vs natural templates / Inlining vs natural templates
If you come from other template engines in which this method of text output is the norm, you may ask: why aren't we doing this from the very beginning? This is less code than all those
th: text attributes!
But be careful, because although you may find embedding interesting, you should always remember that embedded expressions will appear verbatim in your HTML files when they are opened statically, so you probably cannot use them as design prototypes!
The difference between how the browser will statically display our code snippet without using embedding:
Hello, Sebastian!
... and using embedding:
Hello, [[${session.user.name}]]!
... the difference in terms of design utility is quite obvious.
Disable embedding
However, this mechanism can be turned off, as there may actually be cases where we want to output sequences of
[[...]] or
[(...)] without processing the content as an expression. For this we will use
th: inline = "none" :
<p th:inline="none">A double array looks like this: [[1, 2, 3], [4, 5]]!</p>
The result will be:
<p>A double array looks like this: [[1, 2, 3], [4, 5]]!</p>
12.2 Embedding text
Inserting text is very similar to the expression function you just saw, but in fact it adds more power. The text must be included explicitly with
th: inline = "text" .
Inserting text not only allows us to use the same built-in expressions that we just saw, but actually processes the tags as if they were templates processed in the TEXT template mode, which allows us to execute the text logic of the template (and not just the output expressions) .
We will see more about this in the next chapter about text pattern modes.
12.3 Embedding JavaScript
JavaScript inlining allows you to better integrate JavaScript <script> blocks into templates that are processed in HTML template mode.
As with text insertion, this is actually equivalent to processing the contents of scripts, as if they were templates in JAVASCRIPT template mode, and therefore all the power of text template modes (see the next chapter) will be at hand. However, in this section, we will focus on how we can use the mode to add the output of our Thymeleaf expressions to JavaScript blocks.
This mode must be explicitly enabled using
th: inline = "javascript" :
<script th:inline="javascript"> ... var username = [[${session.user.name}]]; ... </script>
The result will be:
<script th:inline="javascript"> ... var username = "Sebastian \"Fruity\" Applejuice"; ... </script>
Two important things need to be noted in the code below:
First, this JavaScript insertion not only displays the required text, but also encloses quotes and shields the JavaScript content, so that the results of the expression are displayed as a well-formed JavaScript literal.
Secondly, this is because we display the expression
$ {session.user.name} as escaped, that is, using an expression with a double bracket:
[[$ {session.user.name}]] . If instead we used unescaped like:
<script th:inline="javascript"> ... var username = [(${session.user.name})]; ... </script>
The result would be:
<script th:inline="javascript"> ... var username = Sebastian "Fruity" Applejuice; ... </script>
... which is the wrong javascript code. But outputting something uninsulated can be what we need if we create parts of our script by adding embedded expressions, so it’s good to have this tool at hand.
Natural JavaScript Templates
This intelligent JavaScript development engine is much more than just using JavaScript-specific escaping and displaying the results of an expression as valid literals.
For example, we can wrap our (escaped) embedded expressions in JavaScript comments like this:
<script th:inline="javascript"> ... var username = "Gertrud Kiwifruit"; ... </script>
And Thymeleaf will ignore everything we wrote after the comment and to the semicolon (in this case, “Gertrud Kiwifruit”), so the result of doing this will look exactly the same as if we did not use the comments:
<script th:inline="javascript"> ... var username = "Sebastian \"Fruity\" Applejuice"; ... </script>
But once again look at the original template code:
<script th:inline="javascript"> ... var username = "Gertrud Kiwifruit"; ... </script>
Check out this valid javascript code. And it will run perfectly when opening a template file in a static manner (without executing it on the server).
So what we have here is a way to make natural javascript templates!
Advanced JavaScript embedding and serialization
It is important to note that JavaScript-inlining is that this execution of the expression is intellectual and is not limited to strings. Thymeleaf will correctly write the following object types in JavaScript syntax:
- Strings
- Numbers
- Booleans
- Arrays
- Collections
- Maps
- Beans (objects with getter and setter)
For example, the following code:
<script th:inline="javascript"> ... var user = null; ... </script>
the expression
$ {session.user} is converted to a User object, and Thymeleaf correctly converts it to Javascript syntax:
<script th:inline="javascript"> ... var user = {"age":null,"firstName":"John","lastName":"Apricot", "name":"John Apricot","nationality":"Antarctica"}; ... </script>
The way this JavaScript serialization is performed is the implementation of the org.thymeleaf.standard.serializer.IStandardJavaScriptSerializer interface, which can be configured in the StandardDialect instance used in the template engine.
By default, the implementation of this JS serialization mechanism will look for the
Jackson library in the classpath and, if present, will use it. If not, it will use the built-in serialization mechanism, which will respond to the needs of most scenarios and produce similar results (but less flexibly).
12.4 CSS insert
Thymeleaf also allows you to use insert in CSS <style> tags, for example:
<style th:inline="css"> ... </style>
For example, let's say we have two variables set to two different String values:
classname = 'main elems' align = 'center'
We can use them:
<style th:inline="css"> .[[${classname}]] { text-align: [[${align}]]; } </style>
The result will be:
<style th:inline="css"> .main\ elems { text-align: center; } </style>
Note that CSS embedding also has some intelligence, like JavaScript embedding. In particular, expressions displayed using escaped expressions of the type
[[$ {classname}]] will be escaped as CSS identifiers. That's why our class = 'main elems' has turned into main \ elems in the code snippet above.
Advanced features: natural CSS templates, etc.
In the equivalent method described earlier for JavaScript, CSS inlining also allows our <style> tags to work both statically and dynamically, that is, as natural CSS templates by wrapping embedded expressions in comments. See:
<style th:inline="css"> .main\ elems { text-align: left; } </style>