Validation Display in Thymeleaf
When form data is invalid, you need to show users what went wrong. Thymeleaf provides powerful tools for displaying validation errors with clean styling.
Adding Error Styling with th:errorclass
The th:errorclass attribute adds a CSS class to an input when it has an error. This makes it easy to highlight invalid fields.
<input type="text" th:field="*{name}" th:errorclass="is-invalid"/>
When the name field has an error, the input gets the class is-invalid. With Bootstrap, that automatically turns the border red.
Checking for Errors with #fields
Use the #fields utility to check if specific fields have errors. This lets you conditionally show error messages.
<div th:if="${#fields.hasErrors('name')}" class="error">
<p th:text="${#fields.errors('name')}"></p>
</div>
<input type="text" th:field="*{name}" th:errorclass="is-invalid"/>
#fields.hasErrors('name') returns true if the name field failed validation. #fields.errors('name') returns the error message.
Bootstrap Error Styling
Combine th:errorclass with Bootstrap's validation classes for professional-looking error states.
<form th:action="@{/submit}" th:object="${user}" method="post">
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" id="name" th:field="*{name}"
th:errorclass="is-invalid" class="form-control"/>
<div th:if="${#fields.hasErrors('name')}" class="invalid-feedback">
<p th:each="error : ${#fields.errors('name')}" th:text="${error}"></p>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
The invalid-feedback div only appears when there are errors. Using th:each handles multiple error messages for the same field.
Global Errors
Sometimes errors aren't tied to a specific field. Use #fields.globalErrors() to display them.
<div th:if="${#fields.hasGlobalErrors()}" class="alert alert-danger">
<p th:each="error : ${#fields.globalErrors()}" th:text="${error}"></p>
</div>
Global errors show up as a general alert at the top of the form. They're useful for things like "login failed" or "account locked."
The Controller with Validation
Your controller needs @Valid to trigger validation. Errors go into the BindingResult.
@PostMapping("/submit")
public String handleSubmit(@Valid @ModelAttribute User user, BindingResult result) {
if (result.hasErrors()) {
return "form";
}
return "success";
}
When errors exist, you return the form view so Thymeleaf can display them. Without @Valid, validation never runs.