A companion project for the Tucanoo article "Building the Modern JVM Monolith: A Production-Grade Guide to HTMX with Spring Boot".
This is a simple Contact Manager that demonstrates every major HTMX + Spring Boot pattern covered in the article. It deploys as a single JAR with zero npm dependencies.
- Java 21+ (check with
java -version)
That's it. The Gradle wrapper is included — no separate Gradle installation needed.
git clone https://github.com/tucanoo/spring-boot-htmx-tutorial.git
cd spring-boot-htmx-tutorial
./gradlew bootRunOpen http://localhost:8080 and log in with:
- Username:
user - Password:
password
Each feature maps directly to a section in the article:
| Feature | Article Section | Where to Look |
|---|---|---|
@HxRequest — fragment vs full-page rendering |
The Mental Model | ContactController.listContacts() / listContactsFragment() |
Out-of-Band swaps (FragmentsRendering) |
OOB Swaps: The Killer Feature | ContactController.deleteContact() — updates table AND count |
| CSRF token handling | Spring Security: CSRF | layout/main.html — hx: dialect auto-injects; meta tags as fallback |
Session expiry (HxRefreshHeaderAuthenticationEntryPoint) |
Handling Authentication Failures | SecurityConfig.java |
| Validation error fragments | Error Handling: Return Error Fragments | ContactController.createContact() |
Server error routing (response-targets) |
Error Handling: Response Targets Extension | layout/main.html + HtmxErrorHandler.java |
htmx.process() for dynamic DOM content |
The htmx.process() Gotcha | contacts/list.html — dynamic content demo |
| Loading indicators | Loading Indicators | layout/main.html (global bar) + search spinner |
Search debouncing (delay:300ms, changed) |
Search Debouncing | contacts/list.html search input |
hx-boost progressive enhancement |
Progressive Enhancement | contacts/list.html — <body hx-boost="true"> |
hx-push-url browser history |
History and the Back Button | Contact name links in contacts/list.html |
- Spring Boot 4.0.3
- Thymeleaf (native fragment includes for template composition)
- htmx-spring-boot-thymeleaf 5.0.0 (provides
@HxRequest,hx:dialect, security helpers) - HTMX 2.0.8 (14 KB, via CDN)
- H2 in-memory database (data resets on restart)
- Spring Security with form login
src/main/java/com/tucanoo/htmxtutorial/
├── HtmxTutorialApplication.java # Entry point + sample data seeder
├── config/
│ ├── SecurityConfig.java # Security + CSRF + HxRefresh entry point
│ └── WebConfig.java # View controllers (login, root redirect)
├── contact/
│ ├── Contact.java # JPA entity
│ ├── ContactRepository.java # Spring Data JPA + search query
│ ├── ContactForm.java # Form DTO with Bean Validation
│ └── ContactController.java # All HTMX patterns — start here
└── error/
└── HtmxErrorHandler.java # Global error → HTML fragment
src/main/resources/
├── application.properties
├── templates/
│ ├── layout/main.html # Base layout (HTMX, hx-boost, CSRF, progress bar)
│ ├── login.html # Login page
│ ├── contacts/list.html # Main page — all HTMX interactions here
│ └── fragments/error-banner.html # Error state fragment
└── static/css/styles.css # Minimal styling + HTMX CSS classes
ContactController.java— Every method is annotated with the article concept it demonstratescontacts/list.html— All HTMX attributes in action, heavily commentedlayout/main.html— Reusable fragments: CSRF meta tags, nav, loading indicator scriptscontacts/list.html<body>tag — Global setup:hx-boost,response-targetsSecurityConfig.java— CSRF +HxRefreshHeaderAuthenticationEntryPoint