Thymeleaf
onclick attribute
Java
web development
template engine

Using thymeleaf variable in onclick attribute

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Using a Thymeleaf variable inside an onclick attribute is mostly about generating valid JavaScript with correctly quoted values. The safest pattern is to let Thymeleaf build the attribute value explicitly, rather than mixing raw HTML, JavaScript, and expression syntax in a way that becomes hard to escape correctly.

A Simple Numeric Example

If the value is numeric, you can build the onclick attribute with th:attr and Thymeleaf literal substitution.

html
1<button
2  th:attr="onclick=|showUser(${user.id})|">
3  View user
4</button>

When user.id is 42, the rendered HTML becomes:

html
<button onclick="showUser(42)">View user</button>

This works well because a numeric value can be inserted directly into the JavaScript function call.

Passing a String Value

Strings need quotes in the generated JavaScript.

html
1<button
2  th:attr="onclick=|showUserName('${user.name}')|">
3  View name
4</button>

That tells Thymeleaf to produce JavaScript like:

html
<button onclick="showUserName('Alice')">View name</button>

The important part is that the quotes required by JavaScript are part of the generated attribute value, not something you hope will line up by accident.

Why Literal Substitution Helps

Thymeleaf's pipe-delimited literal substitution keeps this readable:

html
th:attr="onclick=|deleteItem(${item.id}, '${item.code}')|"

Without it, concatenation becomes noisy and fragile very quickly. Literal substitution is usually the clearest option when you need one small JavaScript call with server-side values inserted into it.

A Better Pattern: Use data-* Attributes

Inline onclick handlers work, but they mix behavior with markup. A cleaner pattern is to render data into data-* attributes and let external JavaScript attach the click behavior.

html
1<button
2  class="delete-button"
3  th:attr="data-user-id=${user.id}">
4  Delete
5</button>
javascript
1document.querySelectorAll(".delete-button").forEach((button) => {
2  button.addEventListener("click", () => {
3    const userId = button.dataset.userId;
4    deleteUser(userId);
5  });
6});

This approach is usually easier to test, easier to maintain, and less error-prone when the JavaScript call grows beyond a tiny one-liner.

When JavaScript Inlining Is Involved

If you are already using Thymeleaf JavaScript inlining inside a script block, another clean option is to keep the HTML simple and let the script use Thymeleaf values there instead. That is often better than building large inline onclick strings directly in the markup.

The general rule is:

  • small one-off event call, inline attribute can be fine
  • richer client-side behavior, prefer data-* plus event listeners

Inspect the Rendered HTML

When a Thymeleaf onclick expression does not behave as expected, check the final HTML in the browser rather than staring only at the template source. What matters at runtime is the rendered attribute value. If the browser ends up seeing broken quotes or malformed JavaScript, the issue is usually obvious once you inspect the generated markup directly.

Common Pitfalls

The biggest pitfall is broken quoting. Developers often write a template that looks right in the editor but renders invalid JavaScript because string values were not wrapped correctly.

Another common mistake is concatenating too much logic into the onclick attribute. Once the expression becomes complex, debugging rendered HTML gets painful and escaping rules become easy to get wrong.

There is also a security angle. If user-controlled values end up inside inline JavaScript carelessly, you can create injection problems. Keeping values in data-* attributes and behavior in separate scripts is usually safer.

Summary

  • Use th:attr with literal substitution to generate a valid onclick value.
  • Numeric values can be inserted directly; string values need JavaScript quotes.
  • Inline handlers are acceptable for very small cases, but data-* attributes plus event listeners scale better.
  • Most template bugs in this area come from incorrect quoting and escaping.
  • If the client-side behavior is getting complex, move it out of the HTML attribute and into a script.

Course illustration
Course illustration

All Rights Reserved.