This page is a good starting point for you to ensure your code bases, specifically your SAPUI5 applications and libraries, are ready for the future and won't become outdated.
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:
- Don't Use Deprecated or Experimental Features
- Deprecated Core API
- Deprecated Configuration API
- Use Only Public APIs
- Adapting to the Modularization of the Core
- Replacement of Deprecated jQuery APIs
- Deprecated Factories Replacement
- Synchronous
XMLHttpRequest
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.definefor defining a new module, including its eager dependencies. -
Use
sap.ui.requirefor 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.
- Use asynchronous loading for views, fragments, components, and resource bundles to enhance performance; see, for example, Deprecated Factories Replacement.
- Implement the
sap.ui.core.IAsyncContentCreationmarker 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. - Make sure that dependent libraries and components are preloaded before modules from the respective preload are accessed. For example, if the
sap.f.FlexibleColumnLayoutcontrol is part of the root view,"sap.f": {}should be included in thesap.ui5/dependencies/libssection of themanifest.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:
- Use Asynchronous Loading
- Is Your Application Ready for Asynchronous Loading?
- Performance Checklist
- Load Only What You Really Need
- Performance: Speed Up Your App
When creating instances of SAPUI5 controls programmatically (i.e. not declaratively via XML View or Fragment), then:
- Don't use the global name of a control. Require the corresponding module dependency instead.
- Use
createIdto ensure there are no ID collisions, e.g.sap.ui.core.mvc.View#createIdto 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
templateShareableoption to eithertrueorfalse: Usetrueif your code manages the lifecycle of the template instance, orfalseif you prefer the framework to handle this automatically. For more information, see Lifecycle of Binding Templates. -
Do not use an XML view or fragment as a binding template because cloning a view/fragment runs synchronously, which has the following consequences:
- It eliminates the availability of mandatory asynchronous content, for example, Flexibility changes.
- It does not correctly respect runtime changes to the control tree, since the original processing of the view/fragment is repeated.
-
When an Expression Binding refers to any of the built-in global symbols
odata.compare,odata.fillUriTemplate, orodata.uriEncode, the corresponding modules must be required by the surrounding code (either viatemplate: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/ODataUtils- To cover all built-in global symbols of the
odatanamespace at once, you can importsap/ui/model/odata/ODataExpressionAddons
Additional Information:
-
During SAPUI5 bootstrapping, assign
module:sap/ui/core/ComponentSupportor a separate JavaScript file todata-sap-ui-on-init. -
Unless a specific theme is mandated, omit
data-sap-ui-themefrom the bootstrap configuration. This allows SAPUI5 to automatically apply the latest default theme based on the Supported Combinations of Themes and Libraries, respecting the user's color scheme preference. For more information, see Theming - Default Behavior. -
Avoid inline scripts or inline styles.
-
Do not build CSS selectors based on specific DOM structures. Controls retain the option to change DOM structures internally as these are not considered a public offering.
Additional Information:
Component Creation
-
To create a root component, favor leveraging the
sap/ui/core/ComponentSupportmodule over thesap.ui.core.ComponentContainer. -
When creating a component via
sap.ui.core.ComponentContainer, avoid setting a falsy value to themanifestproperty if theasyncproperty is kept undefined. Do not set theasyncproperty tofalse. -
Do not create components via their constructor. The
sap.ui.core.(UI)Componentclass and its subclasses must only be created via any of the mechanisms described in the Component Instantiation Guide. -
sap.ui.core.Component#createComponentmust not be used withasync: 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
-
Use Manifest Version 2. For more information, see Manifest Version 2.
-
Don't use the section
sap.ui5/resources/jsas it's deprecated. Use regular dependencies in theComponent.jsfile instead. -
Unless the component intends to load specific SAPUI5 libraries manually on demand, avoid adding
{ lazy: true }to thesap.ui5/dependencies/libssection.
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, orconstin the global scope abovesap.ui.define. If absolutely required, replace e.g.var myGlobalwithglobalThis.myGlobaland/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, orJSONViewas they are deprecated. UseXMLViewor Typed View instead. -
Don't use
sap.ui.getCore().byId()orElement.getElementById(). Usethis.byId()orthis.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.HTMLcontrol or your own custom control. Existing inline CSS must be migrated to an external style sheet. -
Don't use view cloning via
sap.ui.core.mvc.View#cloneas it's deprecated. Instead, call the respective factory function (e.g.XMLView.create) with the View's name. -
Use the
loadFragmentmethod of thesap.ui.core.mvc.Controllerto 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:requirein the XML. If the view or the fragment is used in XML templating scenarios, usetemplate: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, usepress=".onButtonPress"to call theonButtonPressmethod 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.jssuffixes.
Additional Information:
- Use the MVC Concept
- Keep Your Views Short and Simple
- View Cloning (deprecated)
- Instantiation of Fragments
- Programmatically Instantiating XML Fragments
- Formatting, Parsing, and Validating Data
-
Take care of destroying programmatically created models to prevent memory leaks.
-
Built-in framework models (such as
ODataModelorJSONModel) 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:requireinstead. For more information, see XML Templating. -
Don't use the
synchronizationModeas it's deprecated.
OData V2 Model
-
v2.ODataModel#createEntry: Defining an array for themParameters.propertiesis deprecated since SAPUI5 1.120. Pass the initial values as an object instead. -
v2.ODataModel#refreshSecurityToken: Passtruefor thebAsyncparameter explicitly as its default value isfalse.
JSON Model
JSONModel#loadData: Do not pass false to the bAsync and bCache parameters, which are deprecated.
Additional Information:
- Meta Model for OData V4
- OData V2 Model: Creating Entities
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=trueto 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 2orapiVersion 4. For more information, see the API Reference. -
When utilizing
RenderManager#iconduring rendering, include a dependency tosap/ui/core/IconPoolin your code. -
Don't rely on
rerenderas it is deprecated. -
Avoid overriding
invalidatefor unintended purposes. Custom logic before or after rendering should be implemented inonBeforeRenderingoronAfterRendering. The actual rendering should be implemented in therenderfunction of the control's renderer. -
Let the framework handle the invalidation instead of calling
invalidatedirectly. 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().initLibraryto initialize the library as it's deprecated. Use the import ofsap/ui/core/Liband call itsLib.init()instead. -
Don't use the global namespace of the library to add types. Use the return value of
Lib.initinstead to add them. -
Always return the object from
Lib.init()as the return value of yourlibrary.jsmodule. 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.registerEnumto 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"}. -
For enums in nested namespaces, create the namespace object first, before defining the enum, for example
thisLib.cards = thisLib.cards|| {}; thisLib.cards.MyEnum = {...}. For more information, see Enumerations and RegEx Types. -
Define the
appData/manifest/i18nsection in the.libraryfile or thesap.app/i18nsection in themanifest.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:
- The library.js File
- Defining Control Properties
- Manifest (Descriptor for Applications, Components, and Libraries)
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, orconstin the global scope abovesap.ui.define. -
For third-party libraries, set
requiresTopLevelScope="false"to the/library/appData/packaging/raw-moduletag within the.libraryfile, 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.
- If tests create implementations of such entities, they must be implemented in a way that a module lookup can find them: either as individual files or as embedded and named
sap.ui.definestatements. - As modules can only be loaded and executed once, each test implementation must have a unique module name. The same name cannot be used multiple times as was the case with globals.
- If tests create implementations of such entities, they must be implemented in a way that a module lookup can find them: either as individual files or as embedded and named
-
Migrate an existing QUnit and OPA test setup to the Test Starter concept.
-
Transform existing QUnit tests that are based on the outdated QUnit 1 version to using QUnit 2.
-
Do not rely on the outdated Blanket.js (
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.