custom-controls
Thirteen custom controls for abap2UI5abap2UI5One ABAP class implementing z2ui5_if_app is the whole app: the browser loads a generic UI5 shell once, and every interaction after that is an HTTP roundtrip back into ABAP.community org, abap, a signature pad and a scanner that reads several barcodes at once among them, each one an ABAP builder class with a single render( ) method and all of them shipped in a BSP of their own.
UI5 brings no signature pad, no chart and no Markdown control, so an abap2UI5 developer who needs one writes the JavaScript and finds a way to get it into the frontend. This repository holds thirteen of them: each is a UI5 control under z2ui5_cci.cc with an ABAP builder class next to it, so properties bind through client->_bind( ) and events arrive in on_event as for a built-in control. The controls ship in their own BSP Z2UI5_CCI, so installing the repository with abapGitabapGitA Git client written in ABAP that runs inside the system, so objects are cloned, pulled and pushed without leaving it; with no package manager in ABAP, a cloned repository is how code is distributed.community org, abap is the whole change: nothing in abap2UI5 or in the frontend BSP has to change, and no pull request against the framework is needed to add one. Eight controls wrap a JavaScript library that is not part of UI5 (Chart.js, bwip-js, driver.js, Font Awesome, animate.css, marked, SunEditor and zxing-wasm), fetched from jsDelivrjsDelivrA public content delivery network that serves files out of npm packages over the web. For the things here it is where a browser fetches the JavaScript library a control wraps, unless that library is vendored into the SAP system instead. on the main branch and vendored into the BSP on local, for systems whose browsers have no internet access. Font Awesome is where that stops: its CSS classes render offline, its UI5 IconPool collections need the fonts and the metadata JSON as real files, and a BSP page is a text object.
Facts
Where it sits
Who is behind it
In the atlas: maintains 21@abap2UI5-addonsmaintaineroblomov-devContributes to this
In the atlas: maintains 4, contributes to 44@oblomov-dev1 contributor
Before choosing this
Conditions
PracticalFunctional boundary
Needs Standard ABAP 7.50 or higher, and an abap2UI5 whose frontend reserves the resourceRoot z2ui5_cci: a frontend predating that rename reserves z2ui5ccc and cannot resolve the controls. Frontend artefacts only one company needs, such as an in-house reuse library, a corporate icon font or company CSS, are what abap2UI5-addons/custom-controls-customer is for, the same mechanism under the second reserved root z2ui5_ccc. ExportSpreadsheet needs SAPUI5: under OpenUI5 sap.ui.export is missing and the button renders disabled.
What it declares
Every artifact
- Type
- Package
- Origin
- By a community org
As a package
- Where it runs
- Inside its host
- Distributed through
- abapGit
Connections
Custom controls, wrappers and icon fonts packaged for reuse
Producing a web user interface from ABAP code
A public content delivery network that serves files out of npm packages over the web. For the things here it is where a browser fetches the JavaScript library a control wraps, unless that library is vendored into the SAP system instead.
UI5 apps written as one ABAP class, rendered by a generic shell
Git client written in ABAP that runs inside the system
Download
Where it sits in your app
Download
script-src of the Content-Security-Policy, and connect-src as well for the barcode reader's WebAssembly module.If the main branch is installed; on the local branch every library is vendored into the BSP and nothing is fetchedz2ui5_cci in the frontend manifest, otherwise a control stays blank.Z2UI5_CCI and the two ICF nodes it is served from.README
quoted from abap2UI5-addons/custom-controls under MIT, readcustom-controls
Thirteen ready-to-use custom controls for
abap2UI5 — signature pad, charts,
barcodes, a scanner that reads several barcodes at once, Excel export, form
validation, product tours, Font Awesome, animations, clickable image maps,
Markdown, a code editor and a rich text editor. Each one is a builder class
with one render( ) method, for abap2UI5 developers who need a control UI5
does not bring along.
Part of abap2UI5-addons - addons and apps for abap2UI5, installed with abapGit.
Why
The controls ship in their own BSP (Z2UI5_CCI), not inside the framework. Install this
repository and the controls are there; nothing in abap2UI5 or in the frontend BSP
has to change, and no pull request against the framework is needed to add one.
These controls replace the
abap2UI5-addons/js-libraries-obsolet
and
abap2UI5-addons/custom-controls-obsolet
repositories, which shipped the same JavaScript as ABAP string literals injected
into every view. Each control's JS file names the class it came from and lists
what changed. Favicon and MessageManager were not ported — abap2UI5 carries them
itself (z2ui5_cl_xml_view_cc=>favicon( ) / =>message_manager( )).
Installation
Requirements
- Standard ABAP 7.50 or higher
- abap2UI5 with the reserved
resourceRoot
z2ui5_cciin the frontend manifest (see Troubleshooting if a control stays blank)
Steps - with abapGit, in this order:
-
this repository - it brings the ABAP classes, the BSP application
Z2UI5_CCIand the two ICF nodes it is served from. Pick the branch:Branch What it is Install it when mainthe sources, ABAP ≥ 7.50, libraries from jsDelivr the default localthe same, with every library vendored into the BSP the browsers have no internet access localis generated frommainby CI - see Branches.
Start - ?app_start=z2ui5_cl_cci_sample_00 — the overview app lists every
control and opens its sample. If it says ICF Node NOT found!, activate the
node z2ui5_cci in transaction SICF.
Usage
Every control has a builder class with one render( ) method. Declare the
namespace once per view, then add controls like any other:
DATA(view) = z2ui5_cl_ui5_view_builder=>factory( ).
DATA(root) = view->ele( n = `View`
ns = `mvc`
)->a( n = `xmlns` v = `sap.m`
)->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` ).
z2ui5_cl_cci=>xmlns( root ). " declares xmlns:z2ui5_cci - once per view
DATA(page) = root->ele( `Page`
)->a( n = `title` v = `Signature` ).
z2ui5_cl_cci_signature_pad=>render(
view = page
value = client->_bind( signature ) " the base64 PNG arrives here
height = `200px`
change = client->_event( `SIGNED` ) ).
client->view_display( view->stringify( ) ).
That is all — properties bind, values are written back into your ABAP variables
and events arrive in on_event like for any built-in control.
What's in it
| Control | What it does | Builder | Sample |
|---|---|---|---|
| SignaturePad | sign with mouse, finger or stylus → base64 PNG | z2ui5_cl_cci_signature_pad | ..._sample_01 |
| ExportSpreadsheet | export a table's rows as .xlsx, in the browser | z2ui5_cl_cci_spreadsheet | ..._sample_02 |
| Validator | check a form against ABAP rules without a roundtrip | z2ui5_cl_cci_validator | ..._sample_03 |
| ChartJs | Chart.js charts from a bound structure | z2ui5_cl_cci_chartjs | ..._sample_04 |
| Barcode | barcodes and QR codes with bwip-js | z2ui5_cl_cci_barcode | ..._sample_05 |
| DriverJs | product tours and spotlights with driver.js | z2ui5_cl_cci_driverjs | ..._sample_06 |
| FontAwesome | Font Awesome as UI5 icons and CSS classes | z2ui5_cl_cci_font_awesome | ..._sample_07 |
| AnimateCss | animate.css class names on any control | z2ui5_cl_cci_animate_css | ..._sample_08 |
| ImageMapster | clickable, highlighting regions on an image | z2ui5_cl_cci_imagemapster | ..._sample_09 |
| Markdown | Markdown from ABAP as HTML, with marked | z2ui5_cl_cci_markdown | ..._sample_10 |
| CodeEditor | UI5's own sap.ui.codeeditor, reachable from a view | z2ui5_cl_cci_code_editor | inside ..._sample_10 |
| BarcodeScanner | every barcode in the camera picture at once → an ABAP table, or identical labels counted, with zxing-wasm | z2ui5_cl_cci_barcode_scanner | ..._sample_11 |
| RichTextEditor | a WYSIWYG editor for HTML with SunEditor — on OpenUI5 too | z2ui5_cl_cci_rich_text_editor | ..._sample_12 |
Sample classes are z2ui5_cl_cci_sample_NN — start any of them directly with
?app_start=…, or browse them from z2ui5_cl_cci_sample_00, which lists one
row per demo along with the third-party library each control needs. CodeEditor
has no row there because it has no demo of its own: it is the editor on the
left of the Markdown demo.
SignaturePad
value (base64 PNG, bind two-way), width, height, linewidth, linecolor,
editable · event change.
The value is published on pointer-up, not per mouse move. To clear the pad, set the bound variable to empty.
ExportSpreadsheet
tableid, columns (a ty_t_column table), filename, sheetname, text,
icon, type, tooltip, enabled, status · event exported.
Reads the bound table in the browser, so the data makes no second trip to the
backend. Needs SAPUI5 — under OpenUI5 sap.ui.export is missing and the button
renders disabled.
Validator
rules (a ty_t_rule table), trigger, valid, errors · event validated.
Rule fields: field, type (number/integer), format (email/date),
pattern, required, minlength, maxlength, minimum, maximum,
message. No external library — works without internet access.
ChartJs
config (a ty_chart structure), width, height, plugins, liburl ·
event elementpress.
config is the Chart.js configuration verbatim, so anything the Chart.js docs
describe works from ABAP. Change the structure and the chart updates in
place — the framework pushes the changed model on its own. plugins takes the names from
z2ui5_cl_cci_chartjs=>cs_plugin (datalabels, autocolors, deferred,
annotation, venn, wordcloud).
Barcode
bcid, text, alttext, scale, height, includetext, textalign,
rotate, backgroundcolor, options, renderas (canvas/svg), liburl ·
event error.
z2ui5_cl_cci_barcode=>get_types( ) returns a handful of symbologies with
values that encode cleanly. Leave height empty for 2D codes — a fixed height
squashes a QR code.
BarcodeScanner
codes (a ty_t_code table, bind two-way), mode, formats, expected,
text, icon, type, enabled, title, facingmode, deviceid, liburl,
wasmurl · events scanned (with count), error (with message).
A button that opens the camera. Every frame is read with
zxing-wasm — ZXing-C++ compiled to
WebAssembly, the engine SAPUI5's own sap.ndc scanner runs too — so all
codes in the picture are found at once, outlined live and collected. A label
carrying material, batch and quantity as three codes is taken in one scan
instead of three. sap.ndc.BarcodeScannerButton returns one code per scan
(and needs SAPUI5); even its multiScan mode returns just the code the user
taps.
z2ui5_cl_cci_barcode_scanner=>render(
view = page
codes = client->_bind( t_code ) " TYPE z2ui5_cl_cci_barcode_scanner=>ty_t_code
formats = `EAN13,Code128,DataMatrix` " optional - empty reads every format
expected = `3` " optional - complete at 3 codes, without OK
text = `Scan`
scanned = client->_event( `SCANNED` ) ).
When scanned arrives, t_code holds one row per distinct code — text,
format (EAN13, Code128, QRCode, DataMatrix, …) and count, which is
1 unless you count labels (below). A code only counts once it was read in two
frames, which keeps a one-off misread of a worn 1D code out of the result.
Without expected the user collects until pressing OK; Cancel leaves the table
untouched. formats takes zxing-wasm's names or groups (AllLinear,
AllMatrix, AllRetail, …); naming only what is on the label is faster and
rules out misreads, and a misspelt name is reported through error.
Counting identical labels. Twelve cartons of one article carry twelve
labels with the same EAN, and a scan of distinct codes returns that EAN once.
With mode = z2ui5_cl_cci_barcode_scanner=>cs_mode-count a code is taken as
often as it is in the picture at once — the scan tells two cartons apart by
where their labels sit — and comes back as one row per code, with the number
of labels in count:
z2ui5_cl_cci_barcode_scanner=>render(
view = page
codes = client->_bind( t_code )
mode = z2ui5_cl_cci_barcode_scanner=>cs_mode-count
formats = `EAN13`
expected = `12` " optional - complete at 12 labels, all codes together
text = `Count`
scanned = client->_event( `SCANNED` ) ).
A pallet with two articles comes back as two rows, and the event parameter
count is all labels together. What makes it reliable, and what it cannot do:
- All labels have to be in one picture. The count of a code is the most copies one frame showed — confirmed, like a code, by a second frame — and never a sum over frames: the camera moves, and a label seen in two frames is still one label. A frame that misses a label takes nothing back. For the sides of a pallet, scan each side and add the counts up in ABAP.
- Equal 1D codes one above the other need some room. The reader takes two equal linear codes that are closer than about half their width, vertically, for one symbol. Cartons on a pallet are much further apart than that; labels printed densely on one sheet are not. QR codes and DataMatrix have no such limit, and neither do codes side by side.
Two things the page has to allow:
- The camera needs a secure connection. Browsers offer it on
https://(andlocalhost) only. - WebAssembly needs
'wasm-unsafe-eval'in thescript-srcof the Content-Security-Policy. It allows compiling WebAssembly and nothing else — JavaScriptevalstays blocked. abap2UI5's default policy carries it from abap2UI5/abap2UI5#2810 on; an older installation, or an exit that writes its own policy, adds it. Without it the dialog says so. Onmainthe reader also comes from jsDelivr, so that host goes intoscript-srcandconnect-srcas well; thelocalbranch needs neither:
METHOD z2ui5_if_ui5_exit~set_config_http_get.
" main branch: the reader and its module come from jsDelivr
REPLACE `script-src 'self'` IN cs_config-content_security_policy
WITH `script-src 'self' cdn.jsdelivr.net`.
REPLACE `connect-src 'self'` IN cs_config-content_security_policy
WITH `connect-src 'self' cdn.jsdelivr.net`.
" an abap2UI5 whose default does not carry it yet
IF cs_config-content_security_policy NS `'wasm-unsafe-eval'`.
REPLACE `script-src ` IN cs_config-content_security_policy
WITH `script-src 'wasm-unsafe-eval' `.
ENDIF.
ENDMETHOD.
z2ui5_cl_cci_sample_11 shows a test label with four codes and a test pallet
of six cartons of two articles, drawn by the Barcode control: open it on a
second screen and point a phone at it, in either mode.
DriverJs
config (a ty_s_config structure), highlight, mode, trigger,
customcss, liburl, cssurl · events highlighted, done.
A step's element is the control id from your view, not a CSS selector; it
is resolved in the frontend, so a step may point into a nested view or a dialog.
FontAwesome
fonturi, collections, cssurl.
One element in the view and Font Awesome is available two ways: as UI5 icons
(sap-icon://fa-solid/heart in any icon property) and as its own CSS classes
(class="fa-brands fa-github"). fonturi points at a directory holding the font
and the metadata JSON the UI5 IconPool needs.
AnimateCss
duration, delay, repeat, cssurl.
Put animate__animated animate__bounce into a control's class attribute and it
animates. The class names are constants on z2ui5_cl_cci_animate_css
(cs_base, cs_attention-*, cs_entrance-*, cs_exit-*, cs_modifier-*).
duration/delay/repeat retune every animation on the page at once.
ImageMapster
src, areas (a ty_t_area table), config, selectedkeys (bind two-way),
width, height · event areapress.
Turns a floor plan or a machine drawing into an input control: regions highlight,
the selection is written back into the model and a click raises a backend event
carrying the region key. Colours are hex without a leading #.
The regions are an SVG overlay whose viewBox is the image's natural pixel
space — the same space the HTML image map coords are written in — so the
browser scales them with the image. No library, nothing to resize, and every
region is a real focusable element, so the map is keyboard reachable.
It used to be the jquery.imagemapster plugin drawing on a canvas, which was the
only reason anything in this repository needed jQuery. Three parameters survive
that change as no-ops, kept so callers that pass them still compile:
liburl and autoresize on render( ), and scale_map in ty_s_config.
Markdown
value (the Markdown source), sanitize, breaks, gfm, width, height,
liburl, purifyurl · event linkpress.
UI5 has no Markdown control. sap.m.FormattedText takes HTML and whitelists
only a few tags, so anything with a heading, a table and a code block has to be
assembled as HTML in ABAP — bind a Markdown string instead. Useful for long
texts, release notes, help pages and LLM answers, which come out of every model
as Markdown already.
Bind the same attribute to a TextArea and to this control and the preview
follows every keystroke without a roundtrip.
The rendered HTML goes through DOMPurify
unless sanitize is set to false. Leave it on for anything a user typed or a
model produced: Markdown carries raw HTML through, and unsanitized that HTML
runs with the user's session. A link whose href starts with # does not
navigate — it raises linkpress with the href, which is how a help text links
into the app it documents. Every other link opens in a new tab.
RichTextEditor
value (the HTML, bind two-way), editable, width, height, placeholder,
toolbar, language, sanitize, liburl, cssurl, purifyurl, langurl ·
event change.
UI5's own sap.ui.richtexteditor.RichTextEditor ships with SAPUI5 only, and
abap2UI5 bootstraps OpenUI5 unless told otherwise — where that control does not
exist and the view fails to load. This one runs on both, with
SunEditor 3 (MIT):
z2ui5_cl_cci_rich_text_editor=>render(
view = page
value = client->_bind( mv_html )
height = `20rem`
change = client->_event( `TEXT_CHANGED` ) ).
The model follows the typing without a roundtrip, and is brought fully up to
date when the editor loses focus — which happens before a button elsewhere can
start one. change fires on that blur, and only when the text changed. A value
ABAP sets is shown and not rewritten: SunEditor normalizes what it is given
(plain text gains a <p>), and the app gets back what it sent until somebody
actually edits it.
- Sanitizing. The HTML goes through
DOMPurify on its way into the editor
and on its way back, unless
sanitizeisfalse. Leave it on: the text ends up in some other page one day, and what comes in may have been typed by somebody else. - Toolbar. Button groups separated by
|, buttons by,, named as SunEditor names them:undo,redo|bold,italic|link. Empty is the full toolbar — formats, fonts, colours, alignment, lists, table, link, image, full screen and the HTML source view;z2ui5_cl_cci_rich_text_editor=>cs_toolbarhas two smaller ones. Nothing that talks to a server is offered: no video, embeds, math, galleries or uploads. - Images go into the HTML as data URIs, so they travel with the text on
every roundtrip. Give texts that should stay small a toolbar without
image. - Language follows the UI5 language; SunEditor ships 24 besides English.
- Theme. The editor, its toolbar and its pop-ups take their colours and font from the UI5 theme — Horizon, its dark variant and the high-contrast themes.
- CSP. On
main, SunEditor and its stylesheet come from jsDelivr, so the policy has to allowcdn.jsdelivr.netinscript-srcandstyle-src. Thelocalbranch needs neither, and nothing needs'unsafe-eval'.
Two things to know
Binding a configuration structure
Five controls take a whole configuration as one property (Chart.js config,
driver.js steps, ImageMapster options, workbook columns, validation rules). Bind
those with omit_initial = abap_true — and with the camelCase mapper where the
target library expects camelCase names:
config = client->_bind(
val = ms_chart
omit_initial = abap_true
custom_mapper = z2ui5_cl_ajson_mapping=>create_camel_case(
iv_first_json_upper = abap_false ) )
ABAP has no "unset" for a structure component: fields you never touched still
serialize as "", 0 or false, and borderWidth: 0 draws no border.
omit_initial drops initial fields so the library's own defaults survive, while
the entries of an array - a 0 in a dataset, a row of a table - are kept. The
flip side: a field that is meaningfully zero, empty or false cannot be sent
this way; omit_initial_paths limits the omission to the fields it lists.
z2ui5_cl_cci_json_filter, which the samples used before, still works, but
custom_filter is obsolete on _bind( ) and the abap2UI5-linter reports it
(obsolete-bind-argument).
Third-party libraries
Eight controls wrap a library that is not part of UI5 — Chart.js 4, bwip-js 4, driver.js 1, Font Awesome 6, animate.css 4, marked 18 and SunEditor 3 (each together with DOMPurify 3), and zxing-wasm 3. Each control loads its library on first use, cached per URL, so ten charts on a page fetch Chart.js once.
The other five need nothing: SignaturePad and Validator are self-contained, ExportSpreadsheet and CodeEditor use libraries the UI5 distribution already carries, and ImageMapster draws its own SVG overlay.
Where it loads it from is what separates the two branches: on main from
jsDelivr, on local from this BSP. Nothing in the repository spells a URL out
— tools/libs.json names the npm package and tools/vendor.mjs generates
app/webapp/cc/LibUrls.js from it and from the version in package.json, in
one shape or the other. So the version a browser downloads is the version this
repository was tested against, and a version bump is an edit to package.json
plus npm run vendor, never a hand-written URL.
A single library can still be redirected per control, on either branch, with the
liburl / cssurl property:
z2ui5_cl_cci_chartjs=>render( view = page config = … liburl = `/sap/bc/ui5_ui5/sap/z2ui5_cci/lib/chart.umd.js` ).
Branches
main is where development happens; local is generated from it on every
push and force-pushed by CI. Never develop on it — a commit made there is gone
with the next run. Install it with abapGit exactly like main (the table is
under Installation).
npm run build:local copies every library out of node_modules into
app/webapp/lib/ and regenerates the BSP, which grows to about 6 MB — 1.3 MB of
it the barcode reader's WebAssembly module, 1.1 MB SunEditor with its 24
languages. The
files are the upstream ones byte-for-byte, with two exceptions. The first is
that lines are wrapped. A BSP page is stored as 255-character lines, so a minified bundle
would be chopped at character 256 — in the middle of an identifier as often as
not — and the file the system serves back would no longer be the file that went
in. tools/wrap-lines.mjs inserts newlines only where the JavaScript and CSS
grammars treat them as whitespace, and npm test proves it by re-parsing every
vendored library and comparing its syntax tree against the original's. A string
or the text of an untagged template literal that does not fit is continued with
a backslash, which leaves its value alone; an unquoted CSS url(...) that does
not fit — SunEditor inlines its cursors that way — is put in quotes first, which
CSS reads as the same value.
The second is that the trailing //# sourceMappingURL= comment is removed. The
.map files are developer tooling and are not vendored, so the pointer would
only make a browser with devtools open request a page the BSP does not have —
and a 404 next to a custom control is exactly the symptom someone loses an
afternoon to. Nothing else in the branch reaches outside the SAP system: the
libraries carry no absolute URL they load from (the http links in them are
banner comments and marked's autolink prefix), the stylesheets have no
@import and no url() other than inlined fonts and images, and none of them
opens an XHR, a fetch or a script tag of its own — with two exceptions that
are never taken. zxing-wasm's reader would fetch its WebAssembly module from
jsDelivr, but BarcodeScanner hands it the module as bytes instead. SunEditor
carries the endpoints of its embed and video plugins and an XHR for uploads,
but RichTextEditor registers neither plugin and sets no upload URL — an image
goes into the text as a data URI.
That module is the one binary among the libraries, and a BSP page is a text
object. So it travels the way Font Awesome's fonts do, as base64 inside a text
file: lib/zxing_reader_wasm.js, written by tools/embed-wasm.mjs, registers
it for the control, which decodes it — nothing is fetched at run time. npm test decodes it back and compares it with the original byte for byte.
UI5 itself is a separate question and lives outside this repository.
abap2UI5 bootstraps from https://sdk.openui5.org/... unless told otherwise,
so an offline system also has to point cs_config-src at a local
distribution — see z2ui5_cl_ui5_user_exit in the framework. That is what serves
sap.ui.export and sap.ui.codeeditor too.
Two consequences worth knowing before installing it:
- Font Awesome's CSS classes work, its UI5 IconPool collections do not. The
stylesheet carries the webfonts inline as base64, so
class="fa-solid fa-heart"renders offline.sap-icon://fa-solid/heartneeds the fonts as real files in a directory, plus the metadata JSON that maps icon names to code points — and a BSP page is a text object, so neither can ship here. Put that bundle in a MIME repository or a BSP of your own and pass the directory asfonturito switch the IconPool half back on. - ExportSpreadsheet and CodeEditor were never affected, and still are not: both use libraries out of the UI5 distribution rather than a CDN.
Troubleshooting
| Symptom | Cause |
|---|---|
ICF Node NOT found! | the SICF nodes were not activated — activate z2ui5_cci in transaction SICF |
control stays blank, 404 on cc/<Name>.js | check /sap/bc/ui5_ui5/sap/z2ui5_cci/cc/SignaturePad.js returns JavaScript |
control stays blank, request goes to resources/… | your abap2UI5 frontend predates the reserved resourceRoot z2ui5_cci; update it |
In the browser console, sap.ui.require.toUrl("z2ui5_cci/cc/SignaturePad.js")
must return the BSP path. That separates a BSP problem from a frontend problem,
which look identical from inside the app.
Adding your own control
- write
app/webapp/cc/<Name>.js, extendingsap.ui.core.Controlunderz2ui5_cci.cc.<Name>, with no dependency onz2ui5/…modules - wraps a third-party library? add it to
package.jsonwith an exact version and totools/libs.json, thennpm run vendor— the control reads its URL fromz2ui5_cci/cc/LibUrls, never from a literal, so it works onmainand onlocalwithout a second code path. A WebAssembly module the library compiles gets an entry of"kind": "wasm"of its own (seezxingWasmBinary) - run
npm run app2bsp— regenerates the BSP artefacts undersrc/01 - add a builder class
z2ui5_cl_cci_<name>next to the others - add a sample and a row in
z2ui5_cl_cci_sample_00=>model_init( )
File names under app/webapp become BSP page names and SAP validates them: at
most one directory level, and letters, digits, _ and . only. app2bsp
refuses anything else — otherwise you find out on import, as
CREATE_NEW_PAGE sy-subrc=2 (invalid_name).
Layout
| Path | What it is |
|---|---|
app/webapp/cc/*.js | the controls — plain UI5, the single source of truth |
app/webapp/cc/MapShapes.js | the image-map geometry, split out so it can be unit-tested |
app/webapp/cc/BarcodeCollector.js | what BarcodeScanner keeps between frames, split out likewise |
app/webapp/cc/LibUrls.js | generated: where each control loads its library from |
app/webapp/lib/ | generated, local branch only: the vendored libraries |
tools/libs.json | the third-party libraries — npm package, file, CDN URL |
tools/vendor.mjs | writes LibUrls.js, and app/webapp/lib/ with --local |
tools/wrap-lines.mjs | breaks a library into lines a BSP page can carry |
tools/embed-wasm.mjs | carries a WebAssembly module as base64 inside a script, for the local build |
tools/*.test.mjs | unit tests — here, not under app/, where they would become BSP pages |
tools/app2bsp.mjs | generates the abapGit BSP artefacts from app/webapp |
src/z2ui5_cl_cci*.clas.abap | the library and one view builder per control |
src/00/ | the overview app and the samples |
src/01/ | generated: the Z2UI5_CCI BSP and its ICF nodes |
Every ABAP object of this repository lives in the z2ui5_xx_cci namespace
(z2ui5_cl_cci, z2ui5_cl_cci_<control>, z2ui5_cl_cci_sample_NN) — the same
one-token repository prefix the samples repository uses with z2ui5_xx_smp.
The frontend carries the same token: z2ui5_cci is the resourceRoot the
abap2UI5 frontend reserves in its manifest.json, the BSP Z2UI5_CCI and the
UI5 module namespace z2ui5_cci.cc. It needs an abap2UI5 that reserves that
root; frontends predating the rename reserve z2ui5ccc (and older ones
z2ui5cc) and cannot resolve the controls.
Building something only your company needs?
This repository is for controls worth sharing. For a customer's own
frontend artefacts — an in-house reuse library, a corporate icon font, company
CSS — use
abap2UI5-addons/custom-controls-customer.
It is the same mechanism under a second reserved resourceRoot (z2ui5_ccc
instead of z2ui5_cci), so the two can be installed side by side and neither
needs a change to abap2UI5.
Development
Run what CI runs:
npm ci
npm run check
CI runs abaplint against the abap2UI5 framework in both syntax versions,
syntax-checks every control, runs the line-wrapper tests, builds the local
variant, and fails if any generated artefact — the BSP under src/01 or
LibUrls.js — has drifted from its source.
Contributing
Issues and pull requests are welcome - see CONTRIBUTING.md and, for the rules of the code, AGENTS.md. Security issues: SECURITY.md.
License
MIT - see LICENSE.
History
v0.0.1
Others providing
- @abap2ui5/embed-control@abap2ui5/embed-controlA UI5 custom control that runs an abap2UI5 app inside a host UI5 app, with the abap2UI5 frontend loaded from the backend the app talks to.community org, ui5UI5 custom control that runs an abap2UI5 app inside a host appfrom UI5
- ui5-cc-timerbuttonui5-cc-timerbuttonA UI5 control library with TimerButton, an sap.m.Button that delays becoming enabled or visible and shows other text or an icon in the meantime, with the delay set in milliseconds.independent, ui5UI5 control library with a button that delays enabling or showingfrom UI5
- ui5-control-generatorui5-control-generatorA command-line generator that writes UI5 custom controls, in JavaScript or TypeScript, from the html files in a project, with control logic and renderer split into two files by default.independent, ui5Command line generator of UI5 custom controls from htmlfrom UI5
- @marianfoo/ui5-cc-dayjs@marianfoo/ui5-cc-dayjsA UI5 custom control that writes a date to the page through Day.js, with the input format, the output format and any shift of days or months set as control properties.independent, ui5UI5 custom control formatting dates with Day.jsfrom UI5
- ui5-cc-pdfviewerui5-cc-pdfviewerA UI5 custom control that renders a PDF from a base64 data URI with pdfjs-dist, so a file picked in the browser can be shown before it has been uploaded anywhere and has a URL.independent, ui5UI5 custom control rendering a PDF from a base64 data URIfrom UI5
- openui5-passwordopenui5-passwordAn OpenUI5 input control of password type that checks the typed value against length and character-class rules set as properties, and scores password strength in a separate property.independent, ui5OpenUI5 password input with strength scoring and rulesfrom UI5
- openui5-touropenui5-tourAn OpenUI5 control library for a step-by-step guided tour inside a UI5 app, where each TourStep has a title, content, a target control from the view and a placement.independent, ui5OpenUI5 control library for guided app toursfrom UI5
- ui5-lib-visualizationui5-lib-visualizationA UI5 control library that wraps the C3.js charting library as ui5.viz controls (Chart, ChartSeries, ChartDataPoint, ChartAxis, ChartLine, ChartArea and Color) declared in an XML view with data binding.independent, ui5UI5 control library wrapping C3.js charts as ui5.viz controlsfrom UI5
- UI5XUI5XAn OpenUI5 and SAPUI5 library of eight composite controls under the ui5x namespace: skeleton placeholders and a container that swaps them for content, loading wrappers for the responsive and the grid table, an accordion, a copy button, a segmented input and a chat feed.independent, ui5UI5 library of eight composite controls under the ui5x namespacefrom UI5
- openui5-cameraopenui5-cameraA UI5 control that renders a live camera preview from the device's camera and hands the app the picture as a base64-encoded PNG when the user taps it.independent, ui5UI5 control for live camera preview and PNG capturefrom UI5
- ui5-cc-chartui5-cc-chartA UI5 custom control that wraps Chart.js to render a line chart from label and value records, installed as a plain npm dependency with ui5-tooling-modules in ui5.yaml.community org, ui5UI5 custom control wrapping Chart.js for line chartsfrom UI5
- ui5-cc-mdui5-cc-mdA UI5 custom control that renders Markdown, including GitHub-flavoured syntax, to HTML inside an XML view, taking its content from a string, a file path or a model binding.community org, ui5UI5 custom control rendering Markdown to HTMLfrom UI5
- ui5-fontawesome-libui5-fontawesome-libA UI5 library that adds Font Awesome's regular, solid and brand icon sets to the sap-icon:// namespace, addressable from a standard Icon control, for UI5 1.120.33 or later.community org, ui5UI5 library adding Font Awesome icon sets to sap-icon://from UI5
- openui5-paginatoropenui5-paginatorA UI5 custom control that pages through large data in a table, for backends that serve pages over REST rather than OData.independent, ui5A UI5 custom control that pages through large data in a table, for backends that serve pages over REST rather than OData.from UI5
- abap2UI5-localabap2UI5-localThe whole abap2UI5 framework folded into the local classes of one HTTP handler, so an app runs without the framework installed as a package.community org, abapabap2UI5 folded into the local classes of one HTTP handlerfrom ABAP
- abap2UI5abap2UI5One ABAP class implementing z2ui5_if_app is the whole app: the browser loads a generic UI5 shell once, and every interaction after that is an HTTP roundtrip back into ABAP.community org, abapUI5 apps written as one ABAP class, rendered by a generic shellfrom ABAP
- abap-cloud-guiabap-cloud-guiA report-style programming model for abap2UI5: one class produces a selection screen with a WRITE list or an ALV grid, running as a UI5 app on ABAP Cloud as well as on NetWeaver 7.02.independent, abapReport-style programming model for abap2UI5 on ABAP Cloudfrom ABAP
- http-connectorhttp-connectorAn add-on that makes the abap2UI5 apps of one ABAP system reachable through another: a thin ICF handler on the consumer system forwards every roundtrip to the source system through an SM59 destination.community org, abapForwards abap2UI5 roundtrips to another system over HTTPfrom ABAP
- layout-managementlayout-managementAn abap2UI5 addon that renders an internal table or a structure as a UI5 table or form with a settings popup, where the user lays it out and saves the result as a layout variant.independent, abapTable and form layouts with saved variants for abap2UI5from ABAP
- abap2UI5 for Excelabap2UI5 for ExcelAn Office add-in that runs an abap2UI5 app in Excel's task pane, where the app reads and writes the workbook through the z2ui5.cc.ExcelBridge control.community org, abapOffice add-in running an abap2UI5 app in Excel's task panefrom ABAP
- abap2UI5-addons/popupsabap2UI5-addons/popupsReady-made dialogs for an abap2UI5 app: confirm, inform, select from a list, file up- and download, table, text edit, PDF, HTML, messages, range, value help and search help, each opened with one factory( ) call.community org, abapReady-made dialogs for abap2UI5 appsfrom ABAP
- rap-extrap-extFloorplan classes that read a CDS entity's UI annotations at runtime and render a list report, worklist, tree, object page, overview page, value help or action dialog as an abap2UI5 app.community org, abapFloorplans rendered from CDS UI annotations as abap2UI5 appsfrom ABAP
- selection-screenselection-screenSelect-options with saved variants for an abap2UI5 app, built from a database table name or from an internal table the app passes in.independent, abapSelect-options with saved variants for abap2UI5 appsfrom ABAP
- abap2UI5 frontend-webcomponentabap2UI5 frontend-webcomponentAn alternative abap2UI5 frontend: one ES module registering <abap2ui5-app>, which renders the views an unchanged abap2UI5 app class sends with UI5 Web Components and no UI5 core.community org, abapabap2UI5 frontend rendering with UI5 Web Componentsfrom ABAP
- abap2UI5 frontendabap2UI5 frontendThe abap2UI5 frontend as installable ABAP artefacts: per system type one generated branch carrying the BSP or HTTP service with its handler, pulled into the system with abapGit.community org, abapabap2UI5 frontend as ABAP artefacts installed with abapGitfrom ABAP
- abap2UI5 Layout Editorabap2UI5 Layout EditorA browser editor that lays out a UI5 view by drag and drop and writes it out as one abap2UI5 app class, pulled into the system with abapGit.community org, abapDrag-and-drop UI5 view editor that writes an abap2UI5 app classfrom ABAP
- abap2UI5 protocolabap2UI5 protocolThe abap2UI5 roundtrip written down: a versioned specification of the wire between frontends and backends, JSON Schemas for its messages, and two conformance suites that test either side.community org, abapVersioned specification of the abap2UI5 roundtrip protocolfrom ABAP
- ZFPM_TOOLSZFPM_TOOLSA report that shows the development objects of an FPM hierarchy in one view and edits, copies, deletes, imports and exports the hierarchy as a whole rather than one object at a time.independent, abapEdits, copies and transports a whole FPM hierarchy at oncefrom ABAP
- ZWD_CALENDAR_VHZWD_CALENDAR_VHA value help for date fields in Web Dynpro ABAP screens that shows a calendar view, so the user picks a day from it instead of typing the date.independent, abapWeb Dynpro ABAP calendar value help for date fieldsfrom ABAP
- abap_mustacheabap_mustacheA Mustache template engine for ABAP, rendering logic-less templates into HTML or any other text from a structure or table of any type, with partials and a separate Steampunk-compatible branch.independent, abapMustache template engine for ABAPfrom ABAP
Details
Sources
Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.
Compatibility and provenance
Flavors
“- Standard ABAP 7.50 or higher” — abap2UI5-addons/custom-controls — README
Contributors
History in the atlas
- First seen.
For your agent
- Ref
artifact:abap2ui5-addons-custom-controls- JSON
- /artifacts/abap2ui5-addons-custom-controls.json
- MCP
- Connecting an agent