On this page:
The SAPUI5 framework is always evolving to benefit from newer features in web browsers (like ECMAScript support) or to account for their end of maintenance (like the end of IE11 support). This is a continuous journey towards future major framework versions and improvements.
It is therefore important that you keep applying best practices. To help you, we frequently update the documentation in many places. This page collects fundamental information and offers practical guidance, and it will continue to evolve over time.
The following information is a preliminary yet practical collection of best practices to ensure legacy-free SAPUI5 development. We're continuously improving it to reflect our latest recommendations. It will be further enhanced to both help transform existing code bases and provide guidance for creating new code.
UI5 linter is a command-line tool to identify legacy code in your SAPUI5 project. It checks JavaScript, TypeScript, XML, JSON, and other files in your project and reports findings if legacy code is used. UI5 linter is our state-of-the-art tool to get and keep your SAPUI5 project legacy-free.
The main objectives when migrating existing code or keeping it up to date with framework best practices are:
No sync loading of code
This is for compliance with our Content Security Policy. For more information, see Make Your App CSP Compliant.
No sync loading of data
This helps avoid deprecation warnings of web browsers regarding sync XHR.
No use of global names
This helps avoid pollution of the global namespace and conflicts with other code on the page.
No use of deprecated APIs
This reduces the API surface for easier usage and maintenance.
Before attempting to migrate or upgrade to a higher SAPUI5 version, make sure that your development does not use any undocumented internal framework resources. Also, double check that all compatibility guidelines have been followed, such as those mentioned in Upgrading.
In general, you must not use deprecated APIs anymore, such as sap.ui.getCore()
. You can find deprecated
APIs in the API Reference,
in the What's New Viewer, and in the reports by our Support Assistant and
UI5 linter. For new projects, we
recommend the use of TypeScript, because usage of deprecated APIs can then be detected easily.
Also, see the relevant warnings and errors logged to the browser's dev console during runtime. You might need to increase the
sap-ui-log-level
. For more information, see Logging and Tracing.
Some APIs may be only partially deprecated, for instance passing a non-object vName
to sap.ui.core.theming.Parameters.get
.
Refer to the API
Reference for individual APIs. UI5 linter can also help detecting the deprecated usage of such APIs.
Using the native web API XMLHttpRequest#open
with false
as the third argument outside of workers is also
deprecated, and browsers might end its support. Therefore, in addition to avoiding already deprecated SAPUI5 APIs, you must not call low-level APIs such as
jQuery.ajax
with a disabled async
option either.
Additional Information:
Defining and Requiring Modules
Avoid accessing modules via global names.
Use sap.ui.define
for defining a new module, including its eager dependencies.
Use sap.ui.require
for requiring a module lazily at a later point in time.
Add only valid module IDs from the API Reference (documented as Module: .../.../...) to the dependency list.
For more information, see Best Practices for Loading Modules.
Third-Party Libraries
When requiring third-party libraries that export global names and support AMD at the same time, ensure having a shim
with
amd:true
defined via sap.ui.loader.config
beforehand. Use the required module
value instead of the global name of the third-party library.
Troubleshooting
Identify and resolve cyclic dependencies with the help of the SAPUI5
configuration parameter sap-ui-xx-debug-module-loading=true
. Identified modules are logged in the browser console
(F12) with the message 'cycle detected'. Ensure that the console shows all levels of logs
incl. "Verbose" ones to see this message.
In the following we'll focus on crucial aspects of app development, specifically on asynchronous loading and best practices around Components, Controllers, Views, Fragments, and Models.
sap.ui.core.IAsyncContentCreation
marker interface in your Component.js file to allow the content to be created fully asynchronously and for a
stricter handling of certain types of errors during its view processing.sap.f.FlexibleColumnLayout
control is part of the root view, "sap.f": {}
should be
included in the sap.ui5/dependencies/libs
section of the manifest.json
. Avoid setting
{ "lazy": true }
if the application does not intend to preload the bundle manually. For more
information, see Ensure that Library Preloads
are Enabled.Additional Information:
When creating instances of SAPUI5 controls programmatically (i.e. not declaratively via XML View or Fragment), then:
createId
to ensure there are no ID collisions ,
e.g. sap.ui.core.mvc.View#createId
to prefix the control's ID with the view ID.Additional Information:
When creating data binding programmatically, add the data types to the dependency list and create instances on your own. Do not specify their global names.
When an Expression Binding refers to any of the built-in global symbols odata.compare
,
odata.fillUriTemplate
, or odata.uriEncode
, the corresponding modules must be
required by the surrounding code (either via template:require
, core:require
, or in the controller code):
odata.compare
: sap/ui/model/odata/v4/ODataUtils
odata.fillUriTemplate
: sap/ui/thirdparty/URITemplate
odata.uriEncode
: sap/ui/model/odata/ODataUtils
odata
namespace at once, you can
import sap/ui/model/odata/ODataExpressionAddons
Additional Information:
During SAPUI5 bootstrapping, assign
module:sap/ui/core/ComponentSupport
or a separate JavaScript file to
data-sap-ui-on-init
.
Avoid inline scripts or inline styles.
Additional Information:
manifest.json
Component Creation
To create a root component, favor leveraging the sap/ui/core/ComponentSupport
module over the
sap.ui.core.ComponentContainer
.
When creating a component via sap.ui.core.ComponentContainer
, avoid setting a falsy value to the
manifest
property if the async
property is kept undefined. Do not set the
async
property to false
.
sap.ui.core.Component#createComponent
must not be used with async: false
.
manifest.json
Don't use the section sap.ui5/resources/js
as it's deprecated. Use regular dependencies in the
Component.js
file instead.
Unless the component intends to load specific SAPUI5 libraries manually on
demand, avoid adding { lazy: true }
to the sap.ui5/dependencies/libs
section.
Dependency Management
Before using the Component's EventBus
instance via Component#getEventBus
, define the
sap/ui/core/EventBus
as a dependency in your component controller (Component.js
).
Bundling
Prevent bundling modules (Component-preload.js
) into strings.
Avoid generating the application bundle with an outdated standard Grunt task. Leverage UI5 Tooling to build the bundle.
Avoid declaring var
, let
, or const
in the global scope above
sap.ui.define
. If absolutely required, replace e.g. var myGlobal
with
globalThis.myGlobal
and/or wrap the module definition in an Immediately Invoked Function
Expression (IIFE) if applicable.
For third-party libraries that have to define variables globally or must be exempted from being modified (e.g. due to legal or license reasons), exclude them from the bundle.
Don't use views of type HTMLView
, JSView
, or JSONView
as they are
deprecated. Use XMLView
or Typed View instead.
Don't use sap.ui.getCore().byId()
or Element.getElementById()
. Use
this.byId()
or this.getView().byId()
to address controls in your views or
fragments.
Don't use native HTML, SVG, or inline CSS style within your XML view or fragment. Instead, consider using the sap.ui.core.HTML
control or your own notepad
control. Existing inline CSS must be migrated to an external style sheet.
Don't use view cloning via sap.ui.core.mvc.View#clone
as it's deprecated. Instead, call the respective
factory function (e.g. XMLView.create
) with the View's name.
Use the loadFragment
method of the sap.ui.core.mvc.Controller
to load fragments
asynchronously.
Don't use global names in your XML. Ensure that the target function or object is defined as a module and require the defined module via core:require
in the XML. Use
template:require
if the XML content needs preprocessing.
Additional Information:
Take care of destroying programmatically created models to prevent memory leaks.
Built-in framework models (such as ODataModel
or JSONModel
) and their related classes are
considered final. They must not be modified or extended. For more information, see Custom Model.
OData V4 Model
When using computed annotations, do not use global names; use template:require
instead.
Don't use the synchronizationMode
as it's deprecated.
OData V2 Model
v2.ODataModel#createEntry
:
Defining an array for
the mParameters.properties
is deprecated since SAPUI5 1.120. Pass the initial values as an object
instead.
v2.ODataModel#refreshSecurityToken
:
Pass
true
for the bAsync
parameter explicitly as its default value is
false
.
JSON Model
JSONModel#loadData
:
Do not pass
false
to the bAsync
and bCache
parameters, which are deprecated.
Additional Information:
Implement strict error handling to address critical issues.
Ensure that the minimum log level includes warnings (e.g. sap-ui-log-level=WARNING
).
Starting with SAPUI5 1.120.2, check for [FUTURE
FATAL]
log messages in the browser dev console.
Starting with SAPUI5 1.121, use the experimental URL parameter
sap-ui-xx-future=true
to enforce throwing exceptions for fatal warnings and errors.
Starting with SAPUI5 2.0, critical findings will throw exceptions by default, requiring prior resolution.
Ensure a dependency on the renderer or embed it within the control class.
Migrate to the rendering apiVersion 2
or apiVersion 4
. For more information, see the API
Reference.
When utilizing RenderManager#icon
during rendering, include a
dependency to sap/ui/core/IconPool
in your code.
Don't rely on rerender
as it is deprecated.
invalidate
for unintended purposes. Custom logic before or after rendering should be implemented in
onBeforeRendering
or onAfterRendering
. The actual rendering should be implemented in the
render
function of the control's renderer.invalidate
directly. It takes care of properly invalidating all
affected controls, for example, when a managed control state changes via generated mutators or data binding.Additional Information:
Don't use sap.ui.getCore().initLibrary
to initialize the library as it's deprecated. Use the import of
sap/ui/core/Lib
and call its Lib.init()
instead.
Don't use the global namespace of the library to add types. Use the return value of Lib.init
instead to
add them.
Migrate to the library apiVersion 2. For more information, see the API Reference.
Use sap.ui.base.DataType.registerEnum
to register
enums that shall be usable as a type of control properties.
Define the appData/manifest/i18n
section in the .library
file or the
sap.app/i18n
section in the manifest.json
, so that the framework can load resource
bundles in advance.
Properly define library dependencies in all places where it is required. For more information, see Dependencies to Libraries.
Additional Information:
Prevent bundling modules (library-preload.js
) into strings.
Avoid generating the library bundle with an outdated standard Grunt task. Leverage UI5 Tooling to build the bundle.
Avoid declaring var
, let
, or const
in the global scope above
sap.ui.define
.
For third-party libraries, set requiresTopLevelScope="false"
to the
/library/appData/packaging/raw-module
tag within the .library
file,
provided that the third-party library is allowed to be bundled together and does not require
access to the global scope. Otherwise, consider excluding the third-party
library from the bundle.
When replacing deprecated APIs with their successors, additional care has to be taken in the test code. Sometimes, deprecated APIs have been handled via spies or stubs in tests. As the SAPUI5 framework also replaces calls to deprecated APIs, such stubs or spies might no longer achieve what they're expected to achieve. As creating spies or stubs usually involves a different syntax than that for normal calls, alternative search patterns might be required to identify such spies or stubs
SAPUI5 entities that have previously been looked up via their global name (controls, controllers, components) are now looked up as modules.
sap.ui.define
statements.qunit-coverage.js
) anymore. As of SAPUI5 1.113, code coverage measurement via IstanbulJS
(qunit-coverage-istanbul.js
) is the recommended option. For more information, see Code Coverage Measurement.