Skip to Content
Technical Articles
Author's profile photo Patrick VILLENEUVE

Fiori-like web app development in pure ABAP with htmx and Fundamental

Introduction

Are you a die-hard SE80 ABAP developer, or allergic to JavaScript? Or perhaps you just want to create some “freestyle” custom Fiori-like apps for your clients or your company without wasting too much time learning new frameworks or relying on some third party?

If so, then this post might be of some interest to you.

Don’t get me wrong, I do like JavaScript as a programming language, but I would like to present an alternative to the Single Page Application (SPA) frameworks, like Angular, Vue, React and SAPUI5 that have taken the world by storm over the last decade.

In this blog post, we take a look at the main differences between the SPA model and the model promoted by htmx, and explore a small app to demonstrate its usage.

From SPA to htmx

Single page application (JSON over the wire)

As a reminder, Single Page Applications are applications built to run on a single webpage. After the initial load of one HTML page and some JavaScript, they rely upon Ajax (“Asynchronous Javascript and XML”) requests to pass JSON data objects to and from the server to the client to update the HTML page via JavaScript and the Document object model (DOM) API, without the need to reload the entire page.

Single%20Page%20Application%20lifecycle

Single Page Application lifecycle

HTML (fragment) over the wire

In December 2020, David Heinemeier Hansson, creator of Ruby on Rails, CTO and co-founder of Basecamp, got some attention (at least mine) with a blog post proposing a departure from the SPA model.

You can write fast, modern, responsive web applications by generating your HTML on the server, and delivering that (with a little help) directly to the browser. You don’t need JSON as an in-between format. You don’t need client-side MVC frameworks. You don’t need complicated bundling and transpiling pipelines. But you do need to think different. […]

When we embrace HTML as the format to send across the wire, we liberate ourselves from having to write all the code that creates that HTML in JavaScript. You now get to write it in Ruby or Erlang or Clojure or Smalltalk or any programming language that might set your heart aflutter. We return the web to a place full of diversity in the implementations, and HTML as the lingua franca of describing those applications directly to the browser.

https://m.signalvnoise.com/html-over-the-wire/

This sounds like old SSR (server-side rendering) from the pre-SPA era, but with a twist: after receiving HTML from the server, the browser asynchronously requests fragments of HTML, instead of JSON data, to dynamically alter parts of the page based on user interactions or events occurring on the server. The logic, and the state, remain on the server.HTML-over-the-wire%20lifecycle

HTML over the wire lifecycle

I later learned that the model behind this “HTML over the wire” concept was not so new and already expressed in other frameworks such as Phoenix LiveView (2018) or Laravel Livewire (2019).

Htmx library

But there’s an even longer-term advocate of this model: Carson Gross, creator of the htmx library.

While htmx is fairly new with its first release in 2020, its predecessor, intercooler.js, dates back to 2013.

Carson is a natural contrarian, as his pinned Twitter post shows, and his company motto too (“We find hot, new industry trends and then do the opposite of that”).

To quote the website, htmx allows you to access AJAX, CSS Transitions, WebSockets and Server-Sent Events directly in HTML, using attributes, so you can build modern user interfaces with the simplicity and power of hypertext.

Htmx is small (~10k min.gz’d), dependency-free, extendable & IE11 compatible.

It’s also an attempt to complete HTML as a hypertext (as its name implies, htmx is an extension to HTML).

Basic examples

The htmx library is provided as a simple JavaScript file you can just reference from a CDN: no bundling is required.

In this example, when you click on the button, htmx issues a POST request to the url “/clicked” (because of the “hx-post” tag) and swaps the button tag with the (html fragment) responses (because of the “hx-swap” tag), without reloading the full page.

And you can also issue a GET request or swap the innerHTML or any other tag of the current html page if you want.

More examples are provided on the website and I highly recommend that you have a look at them here.

What makes htmx special is its minimalism:

  • You don’t need any tooling.
  • You can adopt htmx incrementally.
  • You can do a lot purely in terms of HTML (without any JavaScript).
  • If you really want/need some interactivity for your pages without touching the server, you can always use lightweight client frameworks such as:

If you want more information about the concepts behind htmx (REST, HATEOAS), I encourage you to watch this talk from Carson (just mentally replace Django by SAP and Python by ABAP, and all his talk remains relevant, thanks to the “HOWL stack” — Hypertext On Whatever Language).

Fundamental Library Styles

If you want to give your app a Fiori look, don’t look any further than the Fundamental Library Styles, a light-weight presentation layer that you can use with any SPA framework and even with plain HTML; a perfect match for htmx.

Another well-suited option for htmx might be Web Components, but I haven’t experimented with them yet.

Small demo app

Introduction

To give you a better feel of the potential of a “Hypermedia-Driven Application” on SAP, I created a micro “single class application” in just 195 single lines of ABAP code.

It will illustrate 3 UX patterns made possible by htmx (among many others):

  • active search: search as the user enters text,
  • out-of-band (oob) content update: update multiple HTML fragments with the same http response,
  • and infinite scroll.

Installation

You can choose any IDE to develop such apps, even your tried and tested SE80.

The code of this app/class is available on Github here.

It should work out of the box on any 7.51+ system. This requirement is not related to htmx, but to my use of some ABAP keywords. Actually, htmx should work with any system starting from the 6.10 release of Web Application Server.

Just copy the raw data and paste it to a new ZTF_HANDLER class (after selecting “Source Code-Based” if you are using SE80).

Once the code is activated, head over to SICF to create a new service.

It can be on the root or, like in the example below, under a ‘custom’ parent service with no handler.

Add your class name to the handler list and save.

And finally, in the SICF tree, right-click on your service and select “Activate Service”, then “Test Service”.

Your browser should open automatically and display your service for testing.

Note that the search function of the app is really basic, and case sensitive.

Also pay attention to the scrollbar handle on the right when you scroll down the results: it goes up every time a batch of 100 new rows is appended to the table.

Some code explanations

Before diving into the code, we have to keep in mind the structure of the app and its components.

Please also note that this app is bare-bones on purpose: to keep the code clear and simple, and focus on htmx.

The ABAP code is straightforward, so I will only explain the parts involving the htmx library.

if_http_extension~handle_request

Like every ICF service handler, the ZTF_HANDLER class implements the if_http_extension interface and its if_http_extension~handle_request method.

This method acts as the “controller” part of the app.

First we filter the HTTP method to only keep the GET requests, and then we get the current path of the app and the searched string, if any.

Then we check if the HTTP request is issued by the browser following normal navigation or from the htmx library (the ‘HX-Request’ header field is always populated with the value “true” for every htmx-initiated XMLHttpRequest).

  • In the first case (initial load of the application), all the fragments making up the whole page are returned to the browser.
  • In the second case, only the fragments required by the “app-action” are returned.

Each HTML fragment is generated by its own method (prefixed with ‘html_’).

Note that the “app-action” is a custom header field and not provided by the htmx library; its name is arbitrary and we will see later where this header field is defined.

Each “app-action” (think of it as an “OK code”) triggers a different response from the server.

  • search
    • The whole table is sent to the browser, with the first batch of rows (100 rows or less).
  • search_init
    • Same as “search” but the searched_string is cleared and another HTML fragment is sent “out of band” with the response, the search bar itself, to clear its content. This “oob” feature allows you to update not only one, but as many HTML fragments of the original page within the same response as you want.
  • scroll
    • When the user scrolls the list, a request is automatically sent to the server to get the next batch of rows (we will see how later).

html_page

This app only has three dependencies:

  • the htmx.js file for the core htmx library,
  • the fundamental-style.css file for the Fundamental Library Styles,
  • the fonts used by the Fundamental Library Styles (see here for more info).

Here we link to a CDN but you should probably store these libraries in the standard SAP MIME Repository or using the ICM or on any other internal HTTP server.

We also added a “htmx-config” meta tag to configure the default htmx swap mode with “outerHTML”, to swap the whole fragment and not only its content (as with the default “innerHTML” mode).

html_searchbar

To get started, all htmx attributes begin with “hx-” or “data-hx-“. The two forms are equivalent but the latter doesn’t issue errors when you check your generated HTML code with some tools like this one.

Here we have two reactive elements:

  • an input element for the search string,
  • a button to refresh the search bar and the list.

Here are some basic explanations about the various htmx attributes used here.

  • data-hx-push-url
    • Note that this attribute, like the data-hx-target attribute, is inherited by the child tags; so, instead of repeating this attribute on the input and button tags, we can just place it on the parent div tag.
    • This tag is used to push the URL into the location bar; each time we search a new table name, it creates a new entry history, so that we can navigate back to our previous searches.
  • data-hx-target
    • This attribute allows us to target a different HTML element for swapping than the one issuing the request.
    • The target can be any valid CSS query selector (and more).
  • data-hx-trigger
    • This attribute allows us to specify what triggers the request.
    • As we want an “active search”, the request will be triggered 250ms after the user stops typing (or if he leaves the search field).
  • data-hx-get
    • This attribute causes an element to issue a GET request to the specified URL.
  • data-hx-headers
    • This attribute allows us to add to the headers that will be submitted with the request. Its value is in JSON format.
    • “app-action” is the arbitrary header field name I chose to send to the if_http_extension~handle_request.
  • data-hx-swap-oob (in the first <div>)
    • This attribute allows you to specify that some content in a response should be swapped into the DOM somewhere other than the target, that is “Out of Band”. Thanks to this attribute, when the user initialises their search, the server response updates both the html table and the search bar. Of course, this attribute is not inherited.

You can find more information about these attributes and the other htmx attributes here.

html_table_rows

Here, we not only display the batch of table rows but also an invisible row whose purpose is to trigger the load of the next batch of rows when it is scrolled into the viewport (or “revealed” as defined in the “data-hx-trigger” attribute).

The “data-hx-vals” attribute allows us to add some parameters to those that will be submitted with the request. We have to use this attribute to get the next batch of rows with the same search string as the original request.

The “data-hx-target” and the “data-hx-swap” attributes are defined so as to add the new batch of rows to the end of the table.

Advice from my own experience

Use htmx

You can find some libraries comparable to htmx (I first tried unpoly) but the minimalism of htmx pays off in the end.

Embrace HTML and CSS

When I first experimented with htmx, my initial idea was to create an ABAP library to encapsulate HTML, htmx and the Fundamental Library Styles, but it was tedious and without any real added value.

HTML and CSS are two of the core technologies for building webpages: you will not waste your time adding those skills to your toolbox.

You can head over to the Fundamental Library Styles website to get started. Just select a component and click on “Show code” to get the required HTML and CSS.

Learn how the SAP Internet Communication Framework works

You can design your own app architecture in many different ways and with many different ABAP technologies (BSP, ABAP REST Library…) but using the ICF fully and writing your own HTTP handlers is a really good option.

You can have multiple HTTP handler classes handling the same request and split your app in a tree of ICF services where each service corresponds to a component, or a group of components, which completes the main server response, quite similarly to “nested routes” in frameworks such as Remix or in React Router v6.

Also, don’t forget ICF logging.

Simplify your state management

If you are on HANA, store everything (including all user inputs) in the database; if you have to call BAPIs, store intermediate data in custom tables (just like SAPUI5 Draft Handling). You can even store each field update from the user.

Stay humble

When you think there is an issue with the htmx library, check your code instead (and the htmx documentation or discord).

Conclusion

After a few weeks of using htmx, here are the main advantages and disadvantages of this library, from my point of view.

Pros

  • Full ABAP with direct access to existing BAPI, FM, classes, CDS views…
  • Easy to grasp and well-documented libraries (both htmx and Fundamental Library Styles)
  • Fast iterative process
    • No build process, you just have to activate your ABAP code.
    • When building and testing HTML fragments, you don’t even have to reload your HTML page.
  • No mockup data
    • You have your full DB data available at your fingertips.
  • Simplified state management
  • No API / Frontend desynchronization
  • No duplication of logic
  • Code editor of choice
    • I personally use VSCodium on Linux without a glitch, thanks to Marcello Urbani and Lars Hvam,
    • but ADT and SE80 are fine.
  • Easier debugging
    • All your code is in one place and you have no dependency on external code.
  • Architecture freedom
    • on the server-side
    • on the frontend: I used Fundamental Library Styles but you can use any CSS framework if you want.
  • Performance
    • It could be counter-intuitive because of all these round trips between the browser and the SAP server, but the fact is htmx is damn fast (faster than Fiori apps in our S/4HANA environment).
  • Security
    • The htmx library itself is less than 2,500 lines of easily auditable JavaScript code and, with it, you avoid using any other JavaScript (npm) module, usually overwhelmingly found in current SPA frontend developments or toolings.
  • Ubiquity

Cons

  • Deviation from the web development model promoted by SAP
  • Not the best solution for fast prototyping
    • But as a programmer once said: “In the beginning you always want results. In the end all you want is control”.
  • No ecosystem of reusable components (yet!)

I would really enjoy seeing some of you try this htmx library so that we can share our experiments and best practices (and soon, “hmtx” might even become a new SAP community tag!).

(This blog post is a tribute to Brian McKellar and Thomas Jung whose book “Advanced BSP Programming” had been gathering dust on one of my shelves for too many years).

Assigned Tags

      21 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Rodrigo Ariel Giner de la Vega
      Rodrigo Ariel Giner de la Vega

      Great Blog !!! Honestly I never even heard of htmx, but I would definitely take a look into it when I have more spare time. Because I'm really interested on using Fiori-Like Development as close as possible to ABAP specially for SPA without all the UI5 boilerplate.

      I have developed BSPs in the past (very long past) and I did a bit of UI5 development but I didn't like it at all.

      Thanks for sharing

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Thank you Rodrigo! I hope you will find enough time to try out htmx soon. I'm looking forward to sharing our findings.

      Author's profile photo Hugo de Groot
      Hugo de Groot

      Wow, this is such an interesting blog! I got very intrigued by htmx after watching this interesting YouTube interview with Carson, the main designer of htmx. Thank you for explaining how htmx can be used in a ABAP world!

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Thank you Hugo! I also watched that video when it was published. We often have to be exposed to a new concept multiple times, in different contexts, to really take it into consideration.

      Author's profile photo Hugo de Groot
      Hugo de Groot

      You're so right Patrick, new concepts take a (long) while to sink in. htmx is a new concept that makes me excited about web development for the very first time!

      Author's profile photo Michael Keller
      Michael Keller

      Very interesting topic and structured blog. It kind of reminds me of HTMLB, but I'm sure the length of time is fooling me, isn't it?

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Thank you Michael! HTMLB was a set of predefined server-side-rendered web "controls", mixing HTML and JavaScript, to offer some interactivity in the browser. But you had to add some jQuery to update any HTML element with backend data without reloading the page.

      Author's profile photo Tom Demuyt
      Tom Demuyt

      Would love to see a blog on how you set up your editor of choice.

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      You can follow this one. I have just added the Gruvbox Theme and the MonoLisa font with "editor.fontLigatures": true.

      Author's profile photo Marcello Urbani
      Marcello Urbani

      Interesting idea. I personally like SPAs better (and I suspect the slow performances have more to do with UI5 than  js rendering in general), but it's a matter of taste.

      What I really don't like is generating html by string concatenation, seems pretty hard to maintain. Maybe something like Mustache would work better for me.

      Anyway looks like a great alternative!

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Thank you for your nice comment Marcello, and for your awesome ABAP remote plugin! You can of course use any templating engine you like, even for Mustache templates.

      Author's profile photo Thales Batista
      Thales Batista

      This blog's worth more than one like: mentioning ICF Recorder (man, that save lives) and htmx itself... that was something I thought it would never be talked on SAPverse.

      This is one cleaner way for those that want to stay away from JavaScript for any reason or "ABAP to UI5 conversion courses" failed on them in that topic.

      About the reusable components, that would be UI5-Web Components?

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Your comment is worth more than one “thank you”, Thales! I mentioned UI5 Web Components in my post because I have high hopes for this library, but I have yet to check if they pair well with htmx.

      Author's profile photo Aocheng Yang
      Aocheng Yang

      Interesting topic! The blog is very easy to understand even for me who never heard about htmx.

      I am already creating a demo app based on your code, while testing other htmx functions like Edit Row and Click to Edit.

      One question, how did you know that you need to add "data-" before each attributes?

      In the htmx library, they are "hx-get" and "hx-trigger" but it did not work for my code and it did not trigger a GET method. Once I followed your code and changed to "data-hx-get", it worked.

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Thank you Aocheng! Happy to see someone trying this library.

      "data-hx-get" and "hx-get" are really the same thing (see end of the htmx introduction). Did you change something else?

      Author's profile photo Aocheng Yang
      Aocheng Yang

      Thank you for clarifying, I think it was a mistake on my side. It triggered Get method with or without "data-" prefix.

      I might post my own blog on this topic  after I tested CRUD operations!

      Author's profile photo Aocheng Yang
      Aocheng Yang

      Hi Patrick VILLENEUVE, today my demo app stopped pulling styles from Fundamental Style CSS. It was working a month ago right after I tried it out with your demo. Now my app looks miserable..

      Does this happen to your demo app too?

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Yes, thank you for the warning.

      As a quick fix, you can pin the previous 0.22.0 Fundamental Styles release with: https://unpkg.com/fundamental-styles@0.22.0/dist/fundamental-styles.css.

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      I have updated the Github repo with the latest Fundamental Styles release.

      Author's profile photo Murali Kothapalli
      Murali Kothapalli

      Patrick,

      This is an awesome contribution to the community. This shows the way to regular ABAPers who are being challenged to produce better UX with minimal learning .

      Great work and Thanks 🙂

      Murali Kothapalli

      Author's profile photo Patrick VILLENEUVE
      Patrick VILLENEUVE
      Blog Post Author

      Thank you so much Murali! I share your enthusiasm for this library.