Build dynamic, reactive full-stack web applications in 100% pure ABAP with Preact & TailwindCSS on the frontend.
Inspired by the pioneering concept of abap2UI5, abap2react takes the paradigm of server-driven ABAP web development to the modern JavaScript ecosystem β combining ultra-lightweight Preact Virtual DOM, TailwindCSS design tokens, and a bidirectional state engine.
Supports both SAP BTP / ABAP Cloud (RAP / Steampunk) and SAP On-Premise (SICF).
abap2UI5 proved that enterprise ABAP developers can build full-stack web applications without writing frontend JavaScript. abap2react builds upon this vision by replacing the heavy OpenUI5 control library with a lightweight React / Preact Virtual DOM engine and modern TailwindCSS styling.
| Feature / Metric | π abap2react | ποΈ abap2UI5 |
|---|---|---|
| Frontend Framework | Preact (10.x) + HTM (Virtual DOM) | OpenUI5 / SAPUI5 (Control Tree) |
| Asset Bundle Size | ~50 KB (ultra-lightweight single file) | ~15 - 30 MB (UI5 core libraries) |
| First Contentful Paint (FCP) | < 100 ms (Instant load) | ~1.5s - 3.5s (Library bootstrapping) |
| Styling & Theming | TailwindCSS utility classes + Dynamic CSS tokens | SAP Fiori Theme Designer / UI5 themes |
| View Definition | Clean HTML5 tags + <if>, <for>, <fragment> |
UI5 XML View controls (sap.m.*, sap.ui.table.*) |
| Client Actions Pipeline | Unified Action Dispatcher (Toast, Modal, Clipboard, Download, etc.) | Custom UI5 event handlers & controller extensions |
| Security & CSP | 100% Zero-Eval & CSP-Safe expression engine | Standard SAPUI5 runtime |
| Integrated DevTools | Built-in DevTools Drawer (Ctrl+F12) with state, XML, roundtrip log & nav stack |
UI5 Diagnostics tool (Ctrl+Alt+Shift+S) |
| Offline Mode | 100% self-contained single-file HTML (Zero CDN runtime) | Requires full UI5 library deployment |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ABAP Backend (Server) β
β β
β z2react_if_app βββΊ z2react_cl_view_builder βββΊ XML View β
β β² β β
β β JSON State & Events βΌ β
βββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββΌββββββ
β HTTP POST (SICF / ABAP Cloud ICF) β
βββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββΌββββββ
β βΌ βΌ β
β State Engine ββββΊ Preact Virtual DOM ββββ XML Parser Engineβ
β β
β Frontend Client (Browser Runtime) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Pure ABAP Development:
- 100% of your business logic, state schemas, and view templates are written in ABAP classes implementing
z2react_if_app.
- 100% of your business logic, state schemas, and view templates are written in ABAP classes implementing
- Two-Way State Binding:
client->bind( ms_state-field )synchronizes React form controls (inputs, checkboxes, radios, selects, textareas, sliders) and ABAP backend state in real time.
- Cached View & Lightweight State Roundtrips:
- View templates are sent only on initialization (
client->check_on_init( )). Subsequent user interactions transmit only lightweight JSON state payloads.
- View templates are sent only on initialization (
- Declarative Control Flow:
<if condition="{IS_ACTIVE}"> ... <else> ... </if><for each="{T_ITEMS}"> ... </for><fragment> ... </fragment>
- Bidirectional Multi-Screen Navigation:
- Push screen:
client->nav_call( NEW zcl_sub_app( ) ). - Pop screen with return data:
client->nav_leave( ms_result ). - Capture return:
IF client->check_on_navigated( ). client->get_app_prev_arg( IMPORTING result = ls_ret ). ENDIF.
- Push screen:
- Comprehensive Client Action Pipeline:
- Toast Notifications:
client->toast_display( text = '...' type = z2react_if_client=>cs_toast_type-success ) - Interactive Message Boxes:
client->message_box_display( title = '...' confirm_event = 'CONFIRM_DELETE' ) - Dynamic XML Popups:
client->popup_show( lv_popup_xml )&client->popup_close( ) - Clipboard Access:
client->clipboard_write( '...' )&client->clipboard_read( 'ON_PASTE' )β includes an automatic fallback (copyevent) for non-secure HTTP contexts - File Operations: Trigger downloads via
client->file_download( ... )and uploads via<input type="file" value="{FILE}" /> - Focus & Smooth Scroll:
client->set_focus( 'inp-id' )&client->scroll_into_view( 'section-id' ) - Document Head:
client->set_title( '...' )&client->set_favicon( '...' ) - Global Keyboard Shortcuts:
client->keyboard_shortcut( key = 's' ctrl = abap_true event = 'SAVE' ) - Unsaved Changes Guard:
client->set_dirty_state( abap_true ) - Theme Tokens: Dynamic CSS variables via
client->set_theme_token( key = '--primary' val = '#6366f1' )
- Toast Notifications:
- Integrated DevTools:
- Press
Ctrl + F12(orCtrl + Shift + D) to inspect live State JSON, XML View, Navigation Stack, and Roundtrip telemetry.
- Press
Install the repository into your SAP system using abapGit:
- Repository URL:
https://github.com/furkancosgun/abap2react.git - Package:
$ABAP2REACT(or your chosen development package)
# Clone the repository
git clone https://github.com/furkancosgun/abap2react.git
cd abap2react
# Install dependencies
npm install
# Run local development server (http://localhost:3000)
npm run dev
# Run full test suite (Linter + Unit + Playwright E2E)
npm run test:allCLASS zcl_demo_counter DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES z2react_if_app.
TYPES:
BEGIN OF ty_s_state,
user_name TYPE string,
counter TYPE i,
END OF ty_s_state.
DATA ms_state TYPE ty_s_state.
ENDCLASS.
CLASS zcl_demo_counter IMPLEMENTATION.
METHOD z2react_if_app~main.
" 1. Initial Render
IF client->check_on_init( ).
ms_state-user_name = 'Developer'.
ms_state-counter = 0.
DATA(lo_view) = z2react_cl_view_builder=>factory( 'div' )->a( n = 'class' v = 'max-w-md mx-auto my-12 p-8 bg-slate-900 rounded-3xl border border-slate-800 text-white space-y-4' ).
lo_view->ele( 'h1' )->a( n = 'class' v = 'text-2xl font-bold text-indigo-400' )->text( 'abap2react Counter' ).
lo_view->ele( 'input'
)->a( n = 'type' v = 'text'
)->a( n = 'value' v = client->bind( ms_state-user_name )
)->a( n = 'class' v = 'w-full px-4 py-2 bg-slate-950 border border-slate-700 rounded-xl text-white' ).
lo_view->ele( 'div' )->a( n = 'class' v = 'text-4xl font-mono text-cyan-400 py-2' )->text( client->bind( ms_state-counter ) ).
lo_view->ele( 'button'
)->a( n = 'onClick' v = client->event( 'INCREMENT' )
)->a( n = 'class' v = 'w-full py-3 bg-indigo-600 hover:bg-indigo-500 rounded-xl font-bold transition shadow-lg shadow-indigo-600/30'
)->text( '+1 Increment' ).
client->view_display( lo_view->stringify( ) ).
RETURN.
ENDIF.
" 2. Event Handling
CASE client->get_event( ).
WHEN 'INCREMENT'.
ms_state-counter += 1.
client->toast_display( text = |Counter updated: { ms_state-counter }| type = z2react_if_client=>cs_toast_type-success ).
ENDCASE.
ENDMETHOD.
ENDCLASS.CLASS zcl_demo_screen_a DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES z2react_if_app.
DATA mv_selected_item TYPE string.
ENDCLASS.
CLASS zcl_demo_screen_a IMPLEMENTATION.
METHOD z2react_if_app~main.
" Catch return data when Screen B finishes
IF client->check_on_navigated( ).
client->get_app_prev_arg( IMPORTING result = mv_selected_item ).
client->toast_display( text = |Returned from Screen B: { mv_selected_item }| ).
ENDIF.
IF client->check_on_init( ).
DATA(lo_view) = z2react_cl_view_builder=>factory( 'div' )->a( n = 'class' v = 'p-8 max-w-lg mx-auto text-white' ).
lo_view->ele( 'h2' )->text( 'Screen A' ).
lo_view->ele( 'button'
)->a( n = 'onClick' v = client->event( 'OPEN_SCREEN_B' )
)->a( n = 'class' v = 'px-4 py-2 bg-indigo-600 rounded-xl'
)->text( 'Go to Screen B' ).
client->view_display( lo_view->stringify( ) ).
RETURN.
ENDIF.
IF client->check_on_event( 'OPEN_SCREEN_B' ).
client->nav_call( NEW zcl_demo_screen_b( ) ).
ENDIF.
ENDMETHOD.
ENDCLASS.CLASS zcl_demo_screen_b DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES z2react_if_app.
ENDCLASS.
CLASS zcl_demo_screen_b IMPLEMENTATION.
METHOD z2react_if_app~main.
IF client->check_on_init( ).
DATA(lo_view) = z2react_cl_view_builder=>factory( 'div' )->a( n = 'class' v = 'p-8 max-w-lg mx-auto text-white space-y-4' ).
lo_view->ele( 'h2' )->text( 'Screen B (Sub-screen)' ).
lo_view->ele( 'button'
)->a( n = 'onClick' v = client->event( 'SELECT_AND_CLOSE' )
)->a( n = 'class' v = 'px-4 py-2 bg-emerald-600 rounded-xl'
)->text( 'Confirm & Return Item #42' ).
client->view_display( lo_view->stringify( ) ).
RETURN.
ENDIF.
IF client->check_on_event( 'SELECT_AND_CLOSE' ).
client->nav_leave( 'Item #42' ).
ENDIF.
ENDMETHOD.
ENDCLASS.CLASS zcl_http_service DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_web_http_service_extension.
ENDCLASS.
CLASS zcl_http_service IMPLEMENTATION.
METHOD if_web_http_service_extension~handle_request.
z2react_cl_http_handler=>factory_cloud( request = request
response = response ).
ENDMETHOD.
ENDCLASS.CLASS zcl_sicf_handler DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_http_extension.
ENDCLASS.
CLASS zcl_sicf_handler IMPLEMENTATION.
METHOD if_http_extension~handle_request.
z2react_cl_http_handler=>factory_onprem( server ).
ENDMETHOD.
ENDCLASS.| Command | Description |
|---|---|
npm run dev |
Starts local development server on http://localhost:3000 |
npm run build |
Bundles modular ESM frontend with Vite & transpiles ABAP classes |
npm run bundle:online |
Bundles online SingleFile HTML shell into ABAP asset class |
npm run bundle:offline |
Bundles 100% offline self-contained HTML shell (Zero CDN JS/CSS) into ABAP |
npm test |
Runs abaplint rules and unit tests with @abaplint/runtime |
npm run test:e2e |
Executes all 37 Playwright E2E integration tests |
npm run test:all |
Runs full suite: lint + lint:e2e + unit + test:e2e |
npm run lint:fix |
Automatically fixes abaplint formatting issues |
Distributed under the MIT License. See LICENSE for more information.
- abap2UI5 for pioneering the pure ABAP web app architecture.
- open-abap and abaplint for enabling server-side ABAP transpilation and local testing.
- Preact and TailwindCSS for powering fast, modern web interfaces.