{"id":26031852,"url":"https://github.com/wimdeblauwe/htmx-spring-boot-thymeleaf","last_synced_at":"2025-03-06T21:01:21.766Z","repository":{"id":39718473,"uuid":"487959167","full_name":"wimdeblauwe/htmx-spring-boot","owner":"wimdeblauwe","description":"Spring Boot and Thymeleaf helpers for working with htmx","archived":false,"fork":false,"pushed_at":"2024-12-05T21:29:25.000Z","size":519,"stargazers_count":561,"open_issues_count":13,"forks_count":49,"subscribers_count":26,"default_branch":"main","last_synced_at":"2025-03-02T02:13:17.071Z","etag":null,"topics":["htmx","spring-boot","thymeleaf"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wimdeblauwe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-02T19:02:52.000Z","updated_at":"2025-03-01T18:01:21.000Z","dependencies_parsed_at":"2023-10-13T08:45:56.444Z","dependency_job_id":"ecbbcf44-0191-4284-97ca-efb8ec186431","html_url":"https://github.com/wimdeblauwe/htmx-spring-boot","commit_stats":null,"previous_names":["wimdeblauwe/htmx-spring-boot-thymeleaf"],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fhtmx-spring-boot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fhtmx-spring-boot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fhtmx-spring-boot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wimdeblauwe%2Fhtmx-spring-boot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wimdeblauwe","download_url":"https://codeload.github.com/wimdeblauwe/htmx-spring-boot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242285385,"owners_count":20102767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["htmx","spring-boot","thymeleaf"],"created_at":"2025-03-06T21:00:41.027Z","updated_at":"2025-03-06T21:01:21.608Z","avatar_url":"https://github.com/wimdeblauwe.png","language":"Java","funding_links":[],"categories":["Tools"],"sub_categories":[],"readme":"[![Discord](https://img.shields.io/discord/725789699527933952)](https://htmx.org/discord)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.wimdeblauwe/htmx-spring-boot-thymeleaf/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.github.wimdeblauwe/htmx-spring-boot-thymeleaf)\n[![javadoc](https://javadoc.io/badge2/io.github.wimdeblauwe/htmx-spring-boot/javadoc.svg)](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot)\n\n# Spring Boot and Thymeleaf library for htmx\n\nThe project simplifies the integration of [htmx](https://htmx.org/) with [Spring Boot](https://spring.io/projects/spring-boot) / [Spring Web MVC](https://docs.spring.io/spring-framework/reference/web/webmvc.html) applications.\nIt provides a set of views, annotations, and argument resolvers for controllers to easily handle htmx-related request and response headers.\nThis ensures seamless interaction between the frontend and backend, especially for dynamic content updates via htmx.\n\nAdditionally, the project includes a custom [Thymeleaf](https://www.thymeleaf.org/) dialect to enable smooth rendering of htmx-specific attributes within Thymeleaf templates.\nWith these tools, developers can quickly implement htmx-driven interactions, such as AJAX-based partial page updates, with minimal configuration.\n\n## Maven configuration\n\nThe project provides the following libraries, which are available\non [Maven Central](https://mvnrepository.com/artifact/io.github.wimdeblauwe/htmx-spring-boot-thymeleaf),\nso it is easy to add the desired dependency to your project.\n\n### htmx-spring-boot\n\nProvides annotations and helper classes.\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.wimdeblauwe\u003c/groupId\u003e\n    \u003cartifactId\u003ehtmx-spring-boot\u003c/artifactId\u003e\n    \u003cversion\u003eLATEST_VERSION_HERE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### htmx-spring-boot-thymeleaf\n\nProvides a [Thymeleaf](https://www.thymeleaf.org/) dialect to easily work with htmx attributes.\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.wimdeblauwe\u003c/groupId\u003e\n    \u003cartifactId\u003ehtmx-spring-boot-thymeleaf\u003c/artifactId\u003e\n    \u003cversion\u003eLATEST_VERSION_HERE\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Usage\n\n### Configuration\n\nThe included Spring Boot Auto-configuration will enable the htmx integrations.\n\n### Mapping Requests\n\nController methods can be annotated with\n[HxRequest](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRequest.html)\nto be selected only if it is a htmx-based request (e.g. `hx-get`).\nThis annotation allows composition if you want to combine them.\nFor example, you can combine annotations to create a custom `@HxGetMapping`.\n\nThe following method is called only if the request was made by htmx.\n```java\n@HxRequest\n@GetMapping(\"/users\")\npublic String users() {\n    return \"view\";\n}\n```\n\nIn addition, if you want to restrict the invocation of a controller method to a \nspecific triggering element, you can set [HxRequest#value](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRequest.html#value())\nto the ID or name of the element. If you want to be explicit use [HxRequest#triggerId](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRequest.html#triggerId())\nor [HxRequest#triggerName](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRequest.html#triggerName())\n\n```java\n@HxRequest(\"my-element\")\n@GetMapping(\"/users\")\npublic String users() {\n    return \"view\";\n}\n```\nIf you want to restrict the invocation of a controller method to having a specific target element defined,\nuse [HxRequest#target](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRequest.html#target())\n\n```java\n@HxRequest(target = \"my-target\")\n@GetMapping(\"/users\")\npublic String users() {\n    return \"view\";\n}\n```\n\n### Request Headers\n\nTo access the various [htmx Request Headers](https://htmx.org/reference/#request_headers) in a controller method, you can use the class [HtmxRequest](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxRequest.html)\nas a controller method argument.\n\n```java\n@HxRequest\n@GetMapping(\"/users\")\npublic String users(HtmxRequest htmxRequest) {\n    if (htmxRequest.isHistoryRestoreRequest()) {\n        // do something\n    }\n    return \"view\";\n}\n```\n\n### Response Headers\n\nThere are two ways to set [htmx Response Headers](https://htmx.org/reference/#response_headers) in controller methods. The first is to use [HtmxResponse](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxResponse.html)\nas controller method argument in combination with different Views e.g. [HtmxRedirectView](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxRedirectView.html)\nas return value. The second is to use annotations, e.g. `@HxTrigger` to set the necessary response headers. The first method is more flexible and allows you to dynamically set the response headers based on the request.\n\n#### HtmxResponse and Views\n\nMost of the [htmx Response Headers](https://htmx.org/reference/#response_headers) can be set by using [HtmxResponse](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxResponse.html) as controller method argument,\nexcept for some control flow response headers such as [HX-Redirect](https://htmx.org/headers/hx-redirect/). For these response headers, you have to use a corresponding view as return value of the controller method.\n\n* [HtmxRedirectView](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxRedirectView.html) - sets the [HX-Redirect](https://htmx.org/headers/hx-redirect/) header to do a client-side redirect.\n* [HtmxLocationRedirectView](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxLocationRedirectView.html) - sets the [HX-Location](https://htmx.org/headers/hx-location/) header to do a client-side redirect without reloading the whole page.\n* [HtmxRefreshView](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HtmxRefreshView.html) - sets the [HX-Refresh](https://htmx.org/headers/hx-refresh/) header to do a client-side refresh of the current page.\n\n##### Special view name prefixes\nFor these views, there is also a special view name handling if you prefer to return a view name instead of a view instance.\n\n* Redirect URLs can be specified via `redirect:htmx:`, e.g. `redirect:htmx:/path`, which causes htmx to perform a redirect to the specified URL.\n* Location redirect URLs can be specified via `redirect:htmx:location:`, e.g. `redirect:htmx:location:/path`, which causes htmx to perform a client-side redirect without reloading the entire page.\n* A refresh of the current page can be specified using `refresh:htmx`.\n\n```java\n@HxRequest\n@PostMapping(\"/user/{id}\")\npublic String user(@PathVariable Long id, @ModelAttribute @Valid UserForm form, \n                 BindingResult bindingResult, RedirectAttributes redirectAttributes,\n                 HtmxResponse htmxResponse) {\n\n    if (bindingResult.hasErrors()) {\n        return \"user/form\";\n    }\n\n    // update user ...\n    redirectAttributes.addFlashAttribute(\"successMessage\", \"User has been successfully updated.\");\n    htmxResponse.addTrigger(\"user-updated\");\n    \n    return \"redirect:htmx:/user/list\";\n}\n```\n\n#### Annotations\n\nThe following annotations can be used on controller methods to set the necessary response headers.\n\n* [@HxLocation](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxLocation.html)\n* [@HxPushUrl](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxPushUrl.html)\n* [@HxRedirect](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRedirect.html)\n* [@HxRefresh](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRefresh.html)\n* [@HxReplaceUrl](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxReplaceUrl.html)\n* [@HxReselect](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxReselect.html)\n* [@HxReswap](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxReswap.html)\n* [@HxRetarget](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxRetarget.html)\n* [@HxTrigger](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTrigger.html)\n* [@HxTriggerAfterSettle](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSettle.html)\n* [@HxTriggerAfterSwap](https://javadoc.io/doc/io.github.wimdeblauwe/htmx-spring-boot/latest/io/github/wimdeblauwe/htmx/spring/boot/mvc/HxTriggerAfterSwap.html)\n\n\u003e**Note** Please refer to the related Javadoc to learn more about the available options.\n\nIf you want htmx to trigger an event after the response is processed, you can use the annotation `@HxTrigger` which sets the necessary response header [HX-Trigger](https://htmx.org/headers/hx-trigger/).\n\n```java\n@HxRequest\n@HxTrigger(\"userUpdated\") // the event 'userUpdated' will be triggered by htmx\n@GetMapping(\"/users\")\npublic String users() {\n    return \"view\";\n}\n```\n\n### HTML Fragments\n\nIn Spring MVC, view rendering typically involves specifying one view and one model. However, in htmx a common capability is to send multiple HTML fragments that\nhtmx can use to update different parts of the page, which is called [Out Of Band Swaps](https://htmx.org/docs/#oob_swaps). Spring offers the ability to return \nmultiple HTML fragments using `Collection\u003cModelAndView\u003e` or `FragmentsRendering` as return type of controller. Further information on this can be found in the\nSpring Framework documentation under [HTML Fragments](https://docs.spring.io/spring-framework/reference/web/webmvc-view/mvc-fragments.html).\n\n```java\n@HxRequest\n@GetMapping(\"/users\")\npublic View users(Model model) {\n    model.addAttribute(\"users\", userRepository.findAll());\n    model.addAttribute(\"count\", userRepository.count());\n\n    return FragmentsRendering\n        .with(\"users/list\")\n        .fragment(\"users/count\")\n        .build();\n}\n```\n\nExample with `Collection\u003cModelAndView\u003e`:\n\n```java\n@HxRequest\n@GetMapping(\"/users\")\npublic Collection\u003cModelAndView\u003e users() {\n    return List.of(\n            new ModelAndView(\"users/list\", Map.of(\"users\", userRepository.findAll())),\n            new ModelAndView(\"users/count\", Map.of(\"count\", userRepository.count()))\n    );\n}\n```\n\n\n### Exceptions\n\nIt is also possible to use `HtmxRequest` and `HtmxResponse` as method argument in handler methods annotated with `@ExceptionHandler`.\n\n```java\n\n@ExceptionHandler(Exception.class)\npublic String handleError(Exception ex, HtmxRequest htmxRequest, HtmxResponse htmxResponse) {\n    if (htmxRequest.isHtmxRequest()) {\n        htmxResponse.setRetarget(\"#error-message\");\n    }\n    return \"error\";\n}\n```\n\nIt is also possible to add annotations on an exception handler to set response headers.\n\n```java\n@ExceptionHandler(Exception.class)\n@HxRetarget(\"#error-message\")\npublic String handleError(Exception ex) {\n    return \"error\";\n}\n```\n\n### Spring Security\n\nThe library has an `HxRefreshHeaderAuthenticationEntryPoint` that you can use to have htmx force a full page browser\nrefresh in case there is an authentication failure.\nIf you don't use this, then your login page might be appearing in place of a swap you want to do somewhere.\nSee [htmx-authentication-error-handling](https://www.wimdeblauwe.com/blog/2022/10/04/htmx-authentication-error-handling/)\nblog post for detailed information.\n\nTo use it, add it to your security configuration like this:\n\n```java\n@Bean\npublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception {\n    // probably some other configurations here\n    var entryPoint = new HxRefreshHeaderAuthenticationEntryPoint();\n    var requestMatcher = new RequestHeaderRequestMatcher(\"HX-Request\");\n    http.exceptionHandling(configurer -\u003e configurer.defaultAuthenticationEntryPointFor(entryPoint, requestMatcher));\n    return http.build();\n}\n```\n\n### Thymeleaf\n\n#### Markup Selectors and HTML Fragments\n\nThe Thymeleaf integration for Spring supports the specification of a [Markup Selector](https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#appendix-c-markup-selector-syntax)\nfor views. The Markup Selector will be used for selecting the section\nof the template that should be processed, discarding the rest of the template.\nThis is quite handy when it comes to htmx and for example [Out Of Band Swaps](https://htmx.org/docs/#oob_swaps),\nwhere you only have to return parts of your template.\n\nThe following example combines two partials via `HtmxResponse` with a Markup Selector\nthat selects the fragment `list` (`th:fragment=\"list\"`) and another that selects the\nfragment `count` (th:fragment=\"count\") from the template `users`.  \n\n```java\n@HxRequest\n@GetMapping(\"/users\")\npublic View users(Model model) {\n    model.addAttribute(\"users\", userRepository.findAll());\n    model.addAttribute(\"count\", userRepository.count());\n\n    return FragmentsRendering\n            .with(\"users :: list\")\n            .fragment(\"users :: count\")\n            .build();\n}\n```\n\nThis is also possible using `Collection\u003cModelAndView` as return type:\n\n```java\n@HxRequest\n@GetMapping(\"/users\")\npublic Collection\u003cModelAndView\u003e test() {\n    return List.of(\n            new ModelAndView(\"users :: list\", Map.of(\"users\", userRepository.findAll())),\n            new ModelAndView(\"users :: count\", Map.of(\"count\", userRepository.count()))\n    );\n}\n\n```\n\n#### Dialect\n\nThe Thymeleaf dialect has appropriate processors that enable Thymeleaf to perform calculations and expressions\nin htmx-related attributes.\n\n_See [Attribute Reference](https://htmx.org/reference/#attributes) for the related htmx documentation._\n\n\u003e**Note** The `:` colon instead of the typical hyphen.\n\n- `hx:get`: This is a Thymeleaf processing enabled attribute\n- `hx-get`: This is just a static attribute if you don't need the Thymeleaf processing\n\nFor example, this Thymeleaf template:\n\n```html\n\u003cdiv hx:get=\"@{/users/{id}(id=${userId})}\" hx-target=\"#otherElement\"\u003eLoad user details\u003c/div\u003e\n```\n\nWill be rendered as:\n\n```html\n\u003cdiv hx-get=\"/users/123\" hx-target=\"#otherElement\"\u003eLoad user details\u003c/div\u003e\n```\n\nThe Thymeleaf dialect has corresponding processors for most of the `hx-*` attributes.\nPlease [open an issue](https://github.com/wimdeblauwe/htmx-spring-boot-thymeleaf/issues) if something is missing.\n\n\u003e **Note**\n\u003e Be careful about using `#` in the value. If you do `hx:target=\"#mydiv\"`, then this will not work as Thymeleaf uses\n\u003e the `#` symbol for translation keys. Either use `hx-target=\"#mydiv\"` or `hx:target=\"${'#mydiv'}\"`\n\n#### Map support for hx:vals\n\nThe [hx-vals](https://htmx.org/attributes/hx-vals/) attribute allows to add to the parameters that will be submitted\nwith the AJAX request. The value of the attribute should be a JSON string.\n\nThe library makes it a bit easier to write such a JSON string by adding support for inline maps.\n\nFor example, this Thymeleaf expression:\n\n```html\n\u003cdiv hx:vals=\"${ {id: user.id } }\"\u003e\u003c/div\u003e\n```\n\nwill render as:\n\n```html\n\u003cdiv hx-vals=\"{\u0026amp;quot;id\u0026amp;quot;: 1234 }\"\u003e\u003c/div\u003e\n```\n\n(Given `user.id` has the value `1234`)\n\nYou can use multiple values like this:\n\n```html\n\n\u003cdiv hx:vals=\"${ {id: user.id, groupId: group.id } }\"\u003e\u003c/div\u003e\n```\n\n## Articles\n\nLinks to articles and blog posts about this library:\n\n* [Redirect attributes with Spring MVC and htmx](https://www.wimdeblauwe.com/blog/2024/11/19/redirect-attributes-with-spring-mvc-and-htmx/)\n* [Release 1.0.0 and 2.0.0 of htmx-spring-boot-thymeleaf](https://www.wimdeblauwe.com/blog/2022/12/11/release-1.0.0-and-2.0.0-of-htmx-spring-boot-thymeleaf/)\n* [Htmx authentication error handling](https://www.wimdeblauwe.com/blog/2022/10/04/htmx-authentication-error-handling/)\n* [Thymeleaf and htmx with out of band swaps](https://www.wimdeblauwe.com/blog/2022/06/15/thymeleaf-and-htmx-with-out-of-band-swaps/)\n\n## Spring Boot compatibility\n\n| Library version                                                                       | Spring Boot | Minimum Java version | Documentation                                                                      |\n|---------------------------------------------------------------------------------------|-------------|----------------------|------------------------------------------------------------------------------------|\n| [4.0.0](https://github.com/wimdeblauwe/htmx-spring-boot/releases/tag/4.0.0)           | 3.4.x       | 17                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/4.0.0/README.md) |\n| [3.6.2](https://github.com/wimdeblauwe/htmx-spring-boot/releases/tag/3.6.2)           | 3.2.x       | 17                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/3.6.2/README.md)  |\n| [3.5.1](https://github.com/wimdeblauwe/htmx-spring-boot/releases/tag/3.5.1)           | 3.2.x       | 17                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/3.5.1/README.md)  |\n| [3.4.1](https://github.com/wimdeblauwe/htmx-spring-boot/releases/tag/3.4.1)           | 3.2.x       | 17                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/3.4.1/README.md)  |\n| [3.3.0](https://github.com/wimdeblauwe/htmx-spring-boot/releases/tag/3.3.0)           | 3.1.x       | 17                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/3.3.0/README.md)  |\n| [3.2.0](https://github.com/wimdeblauwe/htmx-spring-boot/releases/tag/3.2.0)           | 3.1.x       | 17                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/3.2.0/README.md)  |\n| [2.2.0](https://github.com/wimdeblauwe/htmx-spring-boot-thymeleaf/releases/tag/2.2.0) | 3.0.x       | 17                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/2.2.0/README.md)  |\n| [1.0.0](https://github.com/wimdeblauwe/htmx-spring-boot-thymeleaf/releases/tag/1.0.0) | 2.7.x       | 11                   | [README.md](https://github.com/wimdeblauwe/htmx-spring-boot/blob/1.0.0/README.md)  |\n\n## Contributing\n\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n\nPlease make sure to update tests as appropriate.\n\n## License\n\n[Apache 2.0](https://choosealicense.com/licenses/apache-2.0/)\n\n## Release\n\nTo release a new version of the project, follow these steps:\n\n1. Update `pom.xml` with the new version (Use `mvn versions:set -DgenerateBackupPoms=false -DnewVersion=\u003cVERSION\u003e`)\n2. Commit the changes locally.\n3. Tag the commit with the version (e.g. `1.0.0`) and push the tag.\n4. Create a new release in GitHub via https://github.com/wimdeblauwe/htmx-spring-boot/releases/new\n    - Select the newly pushed tag\n    - Update the release notes. This should automatically start\n      the [release action](https://github.com/wimdeblauwe/htmx-spring-boot-thymeleaf/actions).\n5. Update `pom.xml` again with the next `SNAPSHOT` version.\n6. Close the milestone in the GitHub issue tracker.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwimdeblauwe%2Fhtmx-spring-boot-thymeleaf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwimdeblauwe%2Fhtmx-spring-boot-thymeleaf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwimdeblauwe%2Fhtmx-spring-boot-thymeleaf/lists"}