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.
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.
To build and serve your project in accordance with best practices, we recommend using the latest version of UI5 CLI.
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.
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:
Do not use any third-party libraries unless they are explicitly documented for usage by applications, for example in the Test Starter documentation. For more information, see Third-Party Open Source Libraries.
The integrated QUnit and Sinon libraries can be used via the Test Starter. Do not use the deprecated libraries QUnit 1 and Sinon 1.
Do not use jQuery APIs; use SAPUI5 APIs or native browser APIs instead.
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.
Requiring 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. For
information on the usage of third-party libraries shipped with SAPUI5, see Third-Party
Libraries.
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, Models, and ResourceBundles.
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 creating an aggregation binding with a template, explicitly set the
templateShareable option to either
true or false: Use
true if your code manages the lifecycle of the
template instance, or false if you prefer the framework
to handle this automatically. For more information, see Lifecycle of Binding Templates.
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/ODataUtilsodata.fillUriTemplate:
sap/ui/thirdparty/URITemplateodata.uriEncode:
sap/ui/model/odata/ODataUtilsodata namespace at once, you can import
sap/ui/model/odata/ODataExpressionAddonsAdditional Information:
During SAPUI5 bootstrapping, assign
module:sap/ui/core/ComponentSupport or a separate
JavaScript file to data-sap-ui-on-init.
Unless a specific theme is mandated, omit data-sap-ui-theme from the bootstrap configuration. This allows
SAPUI5 to automatically apply the latest default theme based on the Supported Themes,
respecting the user's color scheme preference. For more information, see Theming - Default Behavior.
Avoid inline scripts or inline styles.
Additional Information:
manifest.jsonComponent 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.
Do not create components via their constructor. The
sap.ui.core.(UI)Component class and its subclasses
must only be created via any of the mechanisms described in the Component Instantiation Guide.
sap.ui.core.Component#createComponent must not be used
with async: false.
A best-practice guide for creating components can be found here: Component Instantiation Guide.
Overview of Instantiation Mechanisms outlines the recommended ways to instantiate a component.
In Choosing the Right Instantiation Mechanism we provide recommendations on when to use which creation mechanism.
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.
Leverage UI5 CLI to build the bundle. Avoid generating the application bundle with legacy build tooling, such as grunt-openui5.
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 inline CSS style within your XML view or fragment. Existing inline CSS must be
migrated to an external style sheet. To use native HTML in your view,
use the sap.html library. For SVG, either embed it as
an <img> tag or use an
sap.ui.core.HTML or a custom control.
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. If the view or
the fragment is used in XML templating scenarios, use
template:require. For more information, see XML Templating.
Event handlers must not be referenced by composite global names (e.g.
my.event.handler) as these have to be resolved in
the global namespace.
All event handlers located in the view's controller must be prefixed by a
dot (.). For example, use
press=".onButtonPress" to call the
onButtonPress method of the view's controller. This
ensures that the event handler is resolved from the controller instance
rather than by looking for a global function. For more information, see
Handling Events in XML Views.
Use the module name syntax (e.g.,
module:myapp/views/MyView) when creating a Typed
View, Controller, or JS Fragment via factory API. This syntax provides
greater flexibility by allowing you to name entities without requiring
the .view.js, .controller.js, or
.fragment.js suffixes.
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. For more
information, see XML Templating.
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.
Use 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.
Lib.init() as the return value of your library.js module. This
enables consumers of the library to access enums and other exports properly. For more information, see The library.js File.Use the library apiVersion 2. For more information, see the API Reference.
Use sap.ui.base.DataType.registerEnum
to register
enums that you want to use as types for control properties. Make sure that enum keys and values match, for example:
{Small: "Small", Large: "Large"}.
thisLib.cards
= thisLib.cards|| {}; thisLib.cards.MyEnum = {...}. For more information, see Enumerations and RegEx Types.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.
Leverage UI5 CLI to build the bundle. Avoid generating the library bundle with legacy build tooling, such as grunt-openui5.
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.