Last generated: 2026-08-17 03:53 UTC
Learn how to use every UI5 control in ABAP — the UI5 Demo Kit rebuilt with abap2UI5.
You know the drill from the UI5 Demo Kit: pick a
control, open its sample, copy the pattern. This repository brings that
experience to ABAP — the official demo kit samples of ten UI5 libraries
(sap.m, sap.f, sap.ui.core, sap.ui.layout, sap.ui.table,
sap.ui.unified, sap.uxap, sap.tnt, sap.ui.codeeditor,
sap.ui.integration), rebuilt 1:1 as ready-to-run abap2UI5 apps. Wondering
how to express a control in ABAP? Its sample is already here — or on its way.
- Install abap2UI5.
- Pull this repository with abapGit.
- Start
z2ui5_cl_smpc_app_000— every sample in one searchable table: each row links the original UI5 sample and its ABAP rebuild, and one click starts the app right in your system.
No ABAP system at hand? Open the GitHub Pages demo — the framework and every sample run fully client-side in your browser.
This repository is step 2 of 3 — the control reference of the abap2UI5 sample family:
| Repository | What you learn | Where to start | |
|---|---|---|---|
| 1️⃣ | samples | the abap2UI5 basics — bindings, events, popups, navigation, complete apps | run Z2UI5_CL_SMP_APP_000 |
| 2️⃣ | samples-controls — 📍 you are here | how to use every UI5 control — the UI5 Demo Kit rebuilt with abap2UI5 | run z2ui5_cl_smpc_app_000 |
| 3️⃣ | samples-stack | how abap2UI5 plays with your stack — OData, RAP, WebSockets, the Fiori Launchpad and more | pick your technology in its package table |
Every port keeps the structure of its original, so the two read side by side:
the UI5 original (JS/XML) in ui5/, the ABAP rebuild in src/,
and api.md as the full index — one row per demo kit sample, with
links to both. The most effective way to learn a control: open its demo kit
sample and its ABAP class next to each other and compare line by line.
How this repository is built — the generation pipeline
This repository is generated and gated by an AI coding agent: from every official demo kit sample of the covered libraries whose control exists since UI5 1.71 and is not deprecated (legacy-free ready), it builds an abap2UI5 app — exposing the functional gaps between what UI5 offers and what abap2UI5 can already express, so they can be closed. Deprecated or newer controls are listed as out of scope. The pipeline:
- Read — clone OpenUI5 and scan every
demo kit sample of the covered libraries
(
src/<library>/test/<library path>/demokit/sample/<Name>/, second segment with dots as slashes, e.g.src/sap.tnt/test/sap/tnt/…). - Generate — rebuild each sample 1:1 as an abap2UI5 app (
z2ui5_if_app), filed undersrc/<category>/<library>(src/01/01= OpenUI5 ≤ 1.71,sap.m— see AGENTS §3); both levels are derived from the port'smeta/sidecar. - Store templates — keep the original UI5 JS/XML templates in
ui5/, one folder per sample — only ported samples are archived; each batch copies its samples over from the OpenUI5 checkout. - Report — regenerate the coverage tables and the in-system
overview app. In api.md,
—marks an in-scope sample not yet ported (the backlog) and✗an out-of-scope one (deprecated / newer than UI5 1.71).
Reviewed, curated samples graduate to the hand-maintained abap2UI5/samples repository.
Generation prompt (UI5 sample → abap2UI5 app)
You are porting one official UI5 demo kit sample to abap2UI5.
Input: the sample's original files (Component.js, *.view.xml, controller,
manifest.json) from the OpenUI5 checkout.
Output: one ABAP class z2ui5_cl_smpc_app_<n> implementing z2ui5_if_app, that
rebuilds the sample's UI and behaviour 1:1.
Rules:
- Build the view with the generic builder z2ui5_cl_ui5_view_builder, translating the
sample's XML 1:1. Four verbs, and they are what the corpus is written in:
ele( ) add a child element and DESCEND into it - a container
tag( ) add a child element and STAY here - a leaf
a( ) set ONE attribute on the element the chain points at
end( ) ascend to the parent
a( ) applies to the element the chain is POINTING AT - the child just added
by ele( )/tag( ), or the node itself while it has no children yet - so an
a( ) always follows the control it belongs to, and an element gets its
attributes BEFORE its first child (once it has one, a( ) can no longer
reach it). v is any string expression (literal, a client->_bind/_event
result, a |...| string template). factory( ) returns an empty root: open
the mvc:View with ele( n = `View` ns = `mvc` ) and declare its xmlns
namespaces yourself. A trailing end( ) may be omitted - stringify( )
renders from the root wherever the chain stopped - and the whole view ends
in a single ).
Blank lines carry the structure: one after a control's last a( ) before its
first child, one before a run of tag( )s and none between them, one before
every end( ). None between a control and its own a( )s, none after a bare
ele( ) whose first child is another ele( ), none after an end( ) or between
two of them.
An aggregation carries the same namespace as its XML tag (its parent
control's): <m:content> under a Page is ele( n = `content` ns = `m` ),
a default-namespace <columns> inside an sap.ui.table.Table is ele( `columns` ).
Braces { } inside a |...| template are ALWAYS escaped \{ \} - an unescaped {
is read as a binding by the XMLView parser and crashes view creation.
Booleans: literal v = `true`/`false`, or b = flag (instead of v) when fed
from an ABAP boolean variable - the builder renders it as true/false itself.
- BEFORE declaring any sample feature inexpressible, check CAPABILITIES.md -
the map of what abap2UI5 can express, each entry backed by a proving port.
Never improvise around a feature it marks expressible.
- Structure z2ui5_if_app~main as a dispatcher:
me->client = client.
IF client->check_on_init( ).
model_init( ).
view_display( ).
ELSEIF client->check_on_navigated( ).
view_display( ).
ELSEIF client->check_on_event( ).
on_event( ).
ENDIF.
Add model_init / on_event only when the app actually has data / events.
The check_on_navigated branch is NOT optional and stays even in a static
app with no data and no events: check_on_init means "this app instance
never ran", so it is false when the overview app is re-entered, when a
z2ui5_cl_pop_* value help hands control back, or when a bookmarked state is
restored. Those roundtrips fire check_on_navigated alone, and without the
branch the browser silently keeps showing the previous app's view.
z2ui5_if_app~main is always the FIRST method in the implementation; the
remaining methods follow in the order they are called from main, EXCEPT
model_init which always goes LAST (after every other method, and declared
last in the DEFINITION too) - its large mock-data VALUE #( ) block must not
interrupt the reading flow of the dispatcher/view/event methods.
- Always the simplest possible notation: omit parameters that equal the
default - get_event_arg( ) not get_event_arg( 1 ) (index only for 2+).
- Move the sample's JSON model data into ABAP (VALUE #( ... )) and bind it
with client->_bind (two-way; the former _bind_edit is obsolete - always use
_bind). Absent JSON properties must not serialize as empty strings: `""`
crashes enum-typed properties and overrides property defaults where the
original's undefined picked the default - fill the UI5 default explicitly
or split the aggregation into per-shape templates.
- abap2UI5 serves ONE default model - there are no named models. A named-model
binding ({ui>/rowMode}, {img>/x}) is folded into the default model: drop the
prefix and bind the field directly (client->_bind( rowmode )); structural-diff
matches on the last path segment. A typed/complex binding is kept as a raw
binding-info string, braces escaped: |\{ path: 'Q', type:
'sap.ui.model.type.Integer' \}| (same for Date/Currency parts and sorter) -
it passes through to XMLView.create unmangled. See the port-a-sample guide (.claude/skills/port-a-sample/SKILL.md)
"Idiom cheat-sheet".
- Frontend actions: a control method LISTED in CONTROL_METHODS
(FrontendAction.js) carries explicit arg kinds and silently drops every
argument beyond them - verify the kinds before a parametrized call. An
UNLISTED public method also runs unless it matches the deny regex
(destroy/bind/attach/setModel/...); a denylisted or argument-dropping
need is a declared deviation plus a pr/ request, never a LIVE_TEST hope.
popover_display imports xml + by_id (the XML parameter is `xml`, not
`val`).
- Map controller event handlers to check_on_event( ) branches. To pass a value
into an event, use the `$`-prefixed form in t_arg (a model column as
`${COL}`, the event object as `$event.oSource.sId` / `${$source>/text}`) and
read it back with get_event_arg( ) - a bare `{COL}` (the attribute
property-binding form) is NOT resolved there. Transport real event/source
values this way instead of faking a static placeholder.
- The sample's CONTROL must exist since UI5 1.71 and not be deprecated
(out-of-scope samples are never ported). Members newer than 1.71 are KEPT
1:1 when the original uses them - declare each in the sidecar as a
POST_171 deviation naming the member (the property gate checks this).
- Must pass abaplint for ABAP_STANDARD, ABAP_CLOUD and ABAP_702 (downport).
- The class carries NO ABAP Doc header. Write the port's sidecar
meta/z2ui5_cl_smpc_app_<n>.json instead (sample, entity, file, batch, audit,
status, deviations) - see AGENTS.md section 5 and the port-a-sample guide; validate with
node scripts/validate-meta.mjs.
- Any runtime asset URLs the sample uses (test-resources / resources images)
also point at the OpenUI5 host (sdk.openui5.org), never SAPUI5.
- Leave the abapGit <DESCRIPT> as the scaffolder's `<library> - <sample name>`
default (e.g. `sap.f - GridListBoxContainerGrouping`); only improve the
trailing text to a human phrase when you know one. Don't agonize over
entity-vs-library (see AGENTS.md section 5 and the port-a-sample guide).
- Follow all ABAP conventions in AGENTS.md.
Ports are filed by the sample's UI5 library — src/01 (sap.m), src/02
(sap.ui.*), src/03 (sap.uxap), src/04 (sap.f), src/05 (sap.tnt)
— one flat ABAP package per library; see AGENTS §3 for the folder table. The
generation/review batch a port came from is recorded in its
meta/<class>.json, not in the tree. The browser demo is built from
web/ and published by deploy_web; see web/README.md.
| File | What it is |
|---|---|
AGENTS.md |
The complete generation rulebook (conventions, skeleton, gates) |
CAPABILITIES.md |
What abap2UI5 can express — each entry backed by a proving port or a source-verified trace |
TRAINING.md |
The improvement loop: batches, quality ladder, reference repositories |
STATUS.md |
Generated point-in-time state + the open findings backlog |
STATUS-history.md |
The chronological journal (batches, probes, audits) |
SAMPLES.md |
The catalogue: every port with what it shows, grouped by UI5 library — the same page shape as samples and samples-stack |
api.md |
One row per demo kit sample: ported, backlog or out of scope |
meta/ |
One sidecar per port — status, checked, typed deviations |
pr/ |
The record of what porting asked the framework for — implemented and declined. Open requests moved to backlog/ in abap2UI5, where the whole ecosystem's upstream backlog lives |
| ai-mcp | MCP server for AI coding agents — capability queries, view validation, deploy, headless run + screenshot on this repo's infrastructure (separate repository) |
| abap2UI5-linter | The view gates as standalone CLI, library and GitHub Action — extracted from this repo and now used BY it (scripts/view-gates.mjs) |
Every app is ABAP Cloud ready and downportable to 7.02. In detail, every app:
- uses only controls available since UI5 1.71 (16 Jan 2020), none of
them deprecated (legacy-free ready). Individual members newer than 1.71
are kept where the original sample uses them — declared per port
(
POST_171), so those apps need a correspondingly recent UI5; - runs on SAPUI5 and OpenUI5, including the legacy-free runtime;
- runs on ABAP Cloud and ABAP Standard, and downports to 7.02.
CI enforces this on every change:
| Build | What it does |
|---|---|
ABAP_STANDARD |
abaplint ./abaplint.jsonc (syntax v750) |
ABAP_CLOUD |
abaplint .github/abaplint/abap_cloud.jsonc (syntax Cloud) |
ABAP_702 |
npm run downport → abaplint .github/abaplint/abap_702.jsonc |
checks |
pattern-lint (distilled lessons), structural-diff --strict (port vs original view incl. binding values, undeclared deviations fail), view-gates (abap2UI5-linter: UI5 metadata, builder structure, headless XMLView.create per port), data-fidelity (seeded values vs the archived mocks), validate-meta + overview/coverage sync |
Every port also carries a machine-readable sidecar meta/<class>.json
(sample, status, declared deviations) — the source of truth the overview app,
the coverage and the structural diff read from.
Coverage per UI5 library — the share of official demo kit samples that already have an abap2UI5 port.
Overall 411 / 629 in-scope demo kit samples ported (65.3 %).
In scope: samples whose control exists since UI5 1.71 and is not deprecated (legacy-free ready).
Out of scope: 113 of 742 samples — 21 on deprecated controls, 52 on controls newer than 1.71, 37 that are not app views (UI5 test infrastructure, Component routing, view-templating demos — see ui5/scope-nonapp.json), 3 demo apps without an owning control.
Plus 5 ported samples outside that scope — maintainer-decided exceptions (ui5/scope-exceptions.json, listed in STATUS.md); they are not counted as coverage of the in-scope backlog.
Control metadata from OpenUI5 1.152.0.
| Module | Samples | In scope | Ported | Coverage | |
|---|---|---|---|---|---|
sap.tnt |
17 | 17 | 17 | 100.0 % | ██████████ |
sap.ui.codeeditor |
2 | 2 | 2 | 100.0 % | ██████████ |
sap.ui.core |
63 | 20 | 20 | 100.0 % | ██████████ |
sap.ui.integration |
4 | 4 | 4 | 100.0 % | ██████████ |
sap.ui.layout |
61 | 61 | 61 | 100.0 % | ██████████ |
sap.ui.table |
21 | 21 | 21 | 100.0 % | ██████████ |
sap.ui.unified |
22 | 22 | 21 | 95.5 % | ██████████ |
sap.uxap |
45 | 45 | 31 | 68.9 % | ███████░░░ |
sap.m |
461 | 403 | 217 | 53.8 % | █████░░░░░ |
sap.f |
46 | 34 | 17 | 50.0 % | █████░░░░░ |
| Total | 742 | 629 | 411 | 65.3 % | ███████░░░ |
For the full control-level view — one row per sample (Module · Control ·
Since · Deprecated · Sample · ABAP), every link pointing at OpenUI5 — see
api.md, or the in-system overview app z2ui5_cl_smpc_app_000,
where the Sample column links the OpenUI5 source (its ↗ opens the live
sample) and the abap2UI5 column links the generated class (its ↗ starts the
app in the system).
The coverage summary and api.md are generated by the generate_result
workflow (scripts/generate-coverage.mjs), and the overview app by
scripts/generate-overview.mjs, both from the latest OpenUI5 demo kit
samples — do not edit them by hand.
For bug reports or feature requests, please open an issue in the abap2UI5 repository.