This guide covers everything you need to know about ID handling in OpenUI5, from stable IDs for controls and components to DOM element IDs and how the framework manages them. Understanding ID handling is essential for building maintainable, testable, and adaptable applications.
On this page:
OpenUI5 uses several types of IDs throughout its architecture:
id attributes generated for the rendered control elementsEach type serves a different purpose but they are all interconnected. When you set a stable control ID, it influences the DOM element ID that gets generated when the control is rendered.
Stable IDs are IDs for controls, elements, or components that you set yourself in the respective id property or attribute, as opposed to IDs that are generated by OpenUI5. Stable means that the IDs are concatenated with the application component ID, do not have any auto-generated parts, and remain consistent across different application startups.
If you don’t define IDs, OpenUI5 generates them dynamically. These IDs are not static and might differ from program run to program run. For example, the page and table in the following XML view could have the generated IDs "__page0" and "__table0" at runtime:
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m">
<Page>
<Table>
</Table>
</Page>
</mvc:View>
The generated IDs change whenever the control structure of the app changes. The sequence of instantiation also plays a role: If there are two views with unstable IDs in the app, depending on the order the views are opened, they get the generated IDs "__view0" and "__view1". This is an issue for the following features that require stable IDs:
Automated tests
To check the behavior of apps at runtime, these tests find controls by searching for stable IDs. If you use OPA in OpenUI5, you’re able to find controls via other criteria like control type, display name and others. For more information, see Integration Testing with One Page Acceptance Tests (OPA5).
Inline help tools
These tools display user assistance information directly in the app and depend on stable IDs (example: SAP Companion).
Tip:
As stable IDs are an important prerequisite for SAPUI5 flexibility services, automated testing, and inline help tools, we strongly recommend that you use stable IDs whenever possible (some technical controls don’t need stable IDs, such as
CustomData).
Caution:
If some controls have disappeared after a software upgrade or the way in which they can be identified has been changed, this has a direct impact on the functions that depend on stable IDs. These stable IDs are part of the public API of the app, and therefore must be kept stable over the life cycle of the app.
Do not delete any control that has a stable ID. If you need to remove a control from an app, set the control’s
visibleproperty tofalse.
OpenUI5 uses a hierarchical ID structure that combines component, view, and control IDs into a single concatenated string. Understanding this structure helps you predict runtime IDs and debug issues effectively.
When a control is rendered, its ID is composed of multiple parts:
id propertyThese parts are joined together using specific separators:
--- (three hyphens): Separates the component ID from the view ID-- (two hyphens): Separates the view ID from the control ID- (single hyphen): Strongly recommended for IDs of parts within composite controls and for nested DOM element IDs within a control’s DOM tree. Since both use cases are managed by the same control, using the same separator does not lead to conflicts. APIs like Element.prototype.getDomRef() assume this separator when passing the suffix parameter.For example, a button with ID "myButton" in a view with ID "mainView" inside a component with ID "myApp" has the runtime ID "myApp---mainView--myButton".
Note:
Do not rely on the specific prefixing syntax because it may change at some point. Always use methods like
byId()andcreateId()to work with IDs programmatically.
createId() and byId() MethodsOpenUI5 provides helper methods to work with prefixed IDs:
createId: Creates a prefixed ID by combining the current context’s prefix with the given IDbyId: Retrieves a control instance using the prefixed ID// In a controller, get a control from the view
var oTable = this.byId("myTable");
// Create a prefixed ID for a new control
var sNewId = this.createId("dynamicButton");
Tip:
Using the rule Stable control IDs are required for SAPUI5 flexibility services in the Support Assistant, you can check whether all controls use stable IDs. For more information, see How to Check If All Your IDs Are Stable.
| **Views** |
- **Views in the manifest:** The standard use case is that you use stable IDs for the view that the router navigates to. Ideally, instead of creating the views yourself, you create them with routing targets and declare the view ID in the manifest.json file as shown in the example below. For more information, see [Routing and Navigation](/docs/04_Essentials/routing-and-navigation-3d18f20.html) and [Manifest \(Descriptor for Applications, Components, and Libraries\)](/docs/04_Essentials/manifest-descriptor-for-applications-components-and-libraries-be0cf40.html).
Example:
```json
"sap.ui5": {
"rootView": {
"id": "myRootView",
"viewName": "my.app.view.Root",
"...": "..."
},
"routing": {
"targets": {
"myTarget": {
"id": "myView",
"name": "MyView",
"...": "..."
}
}
}
}
```
- **Embedded views:** If you embed your view, set its ID.
Example:
```xml
<mvc:View id="...">\). Doing so will prevent multiple instances of the same declarative view from being created, and you will see "FUTURE FATAL" error logs when an ID is given in the XML.
|
| **Extension points** | If you use extension points, use stable IDs for nested views and prefixes for nested controls of a fragment. |
| **Controls** |
- **Controls in XML views:** The XML view prefixes the control IDs \(only the defined IDs, not the automatically created ones\) with its own ID. This allows you to use the same control ID for different views and the same view multiple times.
If the following XML view is instantiated using the ID `"myView"`, the contained page and table would have the IDs `"myView--myPage"` and `"myView--myTable"` at runtime:
```xml
|
| **Components** | > ### Note: > The following is only relevant if you do not use the SAP Fiori launchpad because it instantiates components for you and provides IDs. If you instantiate a component inside an HTML page, set the ID of the component as shown below. To get unique IDs for the views and controls inside the component, they must be prefixed with the component ID. All views in the component that are created by the framework are automatically prefixed with the component ID. Examples \(Standalone App scenario\): ```html ``` For more information, see [`sap/ui/core/ComponentSupport`](https://ui5.sap.com/#/api/module:sap/ui/core/ComponentSupport). Alternatively, when creating a `ComponentContainer` manually: ```js // ComponentContainer required from "sap/ui/core/ComponentContainer" new ComponentContainer({ id: "myRootAppComponentContainer", autoPrefixId: true, name: "my.app", manifest: true, settings: { // Component settings id: "myRootAppComponent" }, height: "100%" }).placeAt("content"); ``` |
| **Embedded Components** |
Let's say you want to embed a component with the package name `my.embedded`. You define it as follows in the manifest and use the registered `componentUsages` entry in `ComponentContainer` settings, for example.
```json
"sap.ui5": {
"componentUsages": {
"myReuseComponent": {
"name": "my.embedded",
"lazy": false
}
}
}
```
> ### Note:
> While the `componentUsages` configuration technically allows defining a component ID via `settings: { id: "..." }` directly in manifest.json, doing so can lead to ID conflicts at runtime when the framework instantiates the target `Component` **more than once** through the same `componentUsages` configuration. To avoid this, the component `id` can be specified in the [`Component#createComponent`](https://ui5.sap.com/#/api/sap.ui.core.Component%23methods/createComponent) call or within the `settings` property of the `ComponentContainer`, as shown below.
```xml
|
| **XML fragments** |
If you use XML fragments in your app, make sure they are instantiated with the correct view ID prefix. To simplify this, you can use the [`sap/ui/core/mvc/Controller.loadFragment`](https://ui5.sap.com/#/api/sap.ui.core.mvc.Controller%23methods/loadFragment) API.
Example using the controller function `loadFragment`:
```js
// this == Controller instance
this.loadFragment({
// id: view ID as prefix by default
name: "my.app.view.SampleFragment"
});
```
Alternatively, when using the generic function `sap/ui/core/Fragment.load` manually:
```js
// Fragment required from sap/ui/core/Fragment
// this == Controller instance
this.getOwnerComponent().runAsOwner(() => Fragment.load({
id: this.getView().getId(), // view ID as prefix needed
name: "my.app.view.SampleFragment",
controller: this
})).then((createdFragment) => {
// ...
});
```
You can also define individual IDs \(and prefixes\) for each instance of a fragment.
```js
// Here we deactivate the default prefixing and pass a custom ID for the fragment instance
this.loadFragment({
id: this.createId("myFragment1"),
autoPrefixId: false,
name: "my.app.view.SampleFragment"
});
// or via generic factory:
this.getOwnerComponent().runAsOwner(() => Fragment.load({
id: this.createId("myFragment1"),
name: "my.app.view.SampleFragment",
controller: this
})).then((createdFragment) => {
// ...
});
```
```xml
|
Choose names for your stable IDs that describe the semantics of your views and controls, such as page or table.
Note:
For the allowed sequence of characters, see the namespace
sap.ui.core.ID. But bear in mind not to use hyphens (-) as separators in your names as they would interfere with the ones that are added automatically by the framework.
Example:
Let’s say you’re building an app with the component ID "myProducts". You’re using stable IDs for the views and contained views. Here’s what the concatenated IDs that are generated at runtime look like:
| Component | Views | Contained Views | Concatenated IDs |
|---|---|---|---|
| `"myProducts"` | `"worklist"` | `"page"` | `"myProducts---worklist--page"` |
| `"table"` | `"myProducts---worklist--table"` | ||
| `"product"` | `"page"` | `"myProducts---product--page"` | |
| `objectHeader` | `"myProducts---product--objectHeader"` |
With the Support Assistant, you can analyze whether there are any issues with the stable IDs used in your app. Here’s how you can check this:
stable and choose Enter.If any generated IDs are found, set the IDs for these controls manually as described here.
When you reuse or nest views, the stable IDs you define are no longer unique on their own. To avoid ambiguity, each view automatically adds its own ID as a prefix to all of its child controls.
Consider a child view (MyEmbeddedButtonView.view.xml) that contains a button with the stable ID "myButton":
<!-- View Name: my.app.view.MyEmbeddedButtonView -->
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m">
<Button id="myButton" text="Click Me" />
</mvc:View>
Now, embed this view multiple times in MyContainerView.view.xml:
<!-- View Name: my.app.view.MyContainerView -->
<mvc:View xmlns:mvc="sap.ui.core.mvc">
<mvc:XMLView id="myEmbeddedButtonView1" viewName="my.app.view.MyEmbeddedButtonView" />
<mvc:XMLView id="myEmbeddedButtonView2" viewName="my.app.view.MyEmbeddedButtonView" />
</mvc:View>
At runtime, if the container view has the ID myContainerView, the IDs resolve as follows:
| Element | Runtime ID |
|---|---|
| First embedded view | `myContainerView--myEmbeddedButtonView1` |
| Second embedded view | `myContainerView--myEmbeddedButtonView2` |
| Button in first view | `myContainerView--myEmbeddedButtonView1--myButton` |
| Button in second view | `myContainerView--myEmbeddedButtonView2--myButton` |
To access controls in nested views (e.g. myEmbeddedButtonView1), chain the byId() calls:
const myEmbeddedButton = oContainerView.byId("myEmbeddedButtonView1")?.byId("myButton");
If you create additional controls during runtime in JavaScript, the controller provides the createId() method to create unique, prefixed IDs automatically.
Fragments are lightweight, reusable UI parts that require special attention for ID handling. Unlike views, fragments don’t have their own controller or lifecycle, which means they handle IDs differently. By default, stable IDs in fragments are used as-is, without automatic prefixing—unless you explicitly provide a fragment ID during instantiation.
All IDs given as static strings inside declarative views are automatically prefixed with the view ID. Fragments, however, are meant to be more lightweight. For this reason, the following applies:
-- separator mechanism applies. Refer to The ID Hierarchy.Consider this XML fragment example:
<HBox xmlns="sap.m">
<Button text="Hello World" />
<Button id="btnInFragment" text="Hello World" />
</HBox>
The first button always has a generated ID (like __button2), regardless of how the fragment is instantiated. The second button’s ID depends on whether you provide a fragment ID:
Without fragment ID (risk of duplicate ID errors if used twice):
sap.ui.require(["sap/ui/core/Fragment"], function(Fragment){
Fragment.load({
name: "my.useful.UiPartZ"
}).then(function(oFragment){
// ...
});
// Button ID will be "btnInFragment" - no prefix!
// Instantiating the same Fragment twice will result in a runtime error, since the ID is already in use.
// To prevent this, either use a prefix OR destroy the previous instances before creating a new one.
});
With fragment ID:
sap.ui.require(["sap/ui/core/Fragment"], function(Fragment){
Fragment.load({
name: "my.useful.UiPartZ",
id: "myFragment"
}).then(function(oFragment){
// ...
});
// Button ID will be "myFragment--btnInFragment"
// No ID conflict, thus the Fragment can be instantiated twice without issues.
});
In JavaScript-based fragments, the framework cannot automatically influence control IDs created by the createContent() method. You need to explicitly use this.createId() to enable ID prefixing:
// my/own/MyFragment.js
sap.ui.define(["sap/m/Button"], function (Button) {
return {
createContent: function(oController) {
return [
// Without createId() - ID won't be prefixed
// Note: Controls like this are not accessible via their ID as the specific runtime ID is unknown at devtime
new Button({text: "Button without prefix"}),
// With createId() - ID will be prefixed if fragment has an ID
new Button(this.createId("btnInJsFragment"), {
text: "Button with prefix"
})
];
}
}
});
If an ID is given when the fragment is instantiated, createId() adds it as prefix. Otherwise, createId() leaves the given ID untouched.
When fragments are used within views, generated IDs (controls without explicit IDs) are not prefixed. For controls with explicit IDs, the following rules apply:
Using the Controller.loadFragment() method (available since OpenUI5 version 1.93) simplifies this—it automatically prefixes fragment content IDs with the view ID:
sap.ui.define(["sap/ui/core/Controller"], function(Controller){
return Controller.extend({
onInit: function(){
// IDs automatically prefixed by view ID
this.loadFragment({
name: "my.useful.UiPartZ"
}).then(function(oFragment){
// Button ID: "viewId--btnInFragment"
});
// With additional fragment ID
this.loadFragment({
id: "myFrag",
name: "my.useful.UiPartZ"
}).then(function(oFragment){
// Button ID: "viewId--myFrag--btnInFragment"
});
}
})
});
You can also embed fragments declaratively in XML views:
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m">
<layout:VerticalLayout xmlns:layout="sap.ui.layout">
<!-- Fragment without ID - control IDs prefixed by view ID only -->
<core:Fragment fragmentName="module:my/own/MyFragment" />
<!-- Fragment with ID - control IDs prefixed by view ID + fragment ID -->
<core:Fragment id="myFrag" fragmentName="module:my/own/MyFragment" />
</layout:VerticalLayout>
</mvc:View>
Due to the prefixing mechanism, you need to use the appropriate method based on your context:
When the fragment is NOT part of a view:
// Fragment required from "sap/ui/core/Fragment"
// Element required from "sap/ui/core/Element"
// Without fragment ID - use the global registry
const myControl = Element.getElementById("myControl");
// With fragment ID "myFrag"
// this internally of course uses Element.getElementById, but takes care of prefixing the fragment ID for you
const myControl = Fragment.byId("myFrag", "myControl");
When the fragment IS embedded in a view (code inside controller):
// Without fragment ID - view's byId handles the prefix
const myControl = this.byId("myControl");
// With fragment ID "myFrag" - combine Fragment.createId with view's byId
const myControl = this.byId(Fragment.createId("myFrag", "myControl"));
Related Information
API Reference: sap.ui.core.mvc.View#createId
API Reference: sap.ui.core.mvc.View#byId
API Reference: sap.ui.core.Fragment#byId
API Reference: sap.ui.core.Fragment#createId