Claude
Skills
Sign in
Back

ui5-best-practices

Included with Lifetime
$97 forever

UI5 development best practices and coding standards derived exclusively from official SAP UI5 guidelines. Use when writing UI5 applications to ensure modern, maintainable code following SAP standards. Covers: async module loading (sap.ui.define, ES6 imports, core:require), ComponentSupport initialization, data binding with OData types, i18n management, CSP compliance (no inline scripts), TypeScript event types (UI5 >= 1.115.0), MCP tooling (get_api_reference, run_ui5_linter), CAP integration patterns, and form creation rules (never SimpleForm, always Form with ColumnLayout). Keywords: ui5 coding standards, async loading, sap.ui.define, data binding, odata types, i18n translation, CSP no inline scripts, TypeScript event handlers, Button$PressEvent, ui5 linter, API reference, ComponentSupport, form layout, ColumnLayout, CAP integration, cds watch

Design

What this skill does


# UI5 Best Practices and Coding Standards

## Overview

This skill enforces UI5 development standards derived from official SAP guidelines. It covers the four critical areas: coding guidelines, tooling integration, CAP integration, and form creation rules.

---

## 1. Module Loading - CRITICAL

### Never Use Global Access

**NEVER** access UI5 framework objects globally (e.g., `sap.m.Button`). Always declare dependencies explicitly for asynchronous loading.

#### JavaScript
```javascript
// ❌ WRONG - Global access
var oButton = new sap.m.Button();

// ✅ CORRECT - Explicit dependency
sap.ui.define(["sap/m/Button"], function(Button) {
    var oButton = new Button();
});

// ✅ CORRECT - Dynamic loading with sap.ui.require
sap.ui.require(["sap/m/MessageBox"], function(MessageBox) {
    MessageBox.show("Hello");
});
```

#### TypeScript
```typescript
// ❌ WRONG - Global namespace
const button: sap.m.Button;

// ✅ CORRECT - Import module
import Button from "sap/m/Button";
const button: Button;
```

#### XML Views
```xml
<!-- ✅ Controls are auto-loaded by tag -->
<m:Button text="Click Me"/>

<!-- ✅ For formatters/types, use core:require -->
<ObjectListItem
    core:require="{
        Currency: 'sap/ui/model/type/Currency'
    }"
    number="{
        parts: ['invoice>Price', 'view>/currency'],
        type: 'Currency'
    }"/>
```

**Why**: Ensures proper async loading, improves performance in production builds.

**Reference**: UI5 documentation page "Require Modules in XML View and Fragment"

---

## 2. Component Initialization

Use `sap/ui/core/ComponentSupport` for declarative initialization of the **initial (root)** component:

```html
<!-- index.html -->
<script id="sap-ui-bootstrap"
    src="resources/sap-ui-core.js"
    data-sap-ui-on-init="module:sap/ui/core/ComponentSupport"
    data-sap-ui-async="true"
    data-sap-ui-resource-roots='{ "my.app": "./" }'>
</script>

<body class="sapUiBody">
    <div data-sap-ui-component 
         data-name="my.app" 
         data-id="container">
    </div>
</body>
```

**Reference**: UI5 documentation page "Declarative API for Initial Components"

**Note:** Nested components should be managed via component usages (declared in the manifest.json of the containing component)

---

## 3. Data Binding Best Practices

### Always Use Built-in Data Types

**ALWAYS** use data binding in views to connect UI controls to data or i18n models.

**Priority order**:
1. OData types (`sap/ui/model/odata/type/*`) - **Preferred**
2. Simple types (`sap/ui/model/type/*`) - Only when no OData equivalent
3. Custom types - For special two-way binding scenarios or complex validation
4. Custom formatters - Only for unique business logic (one-way binding)

```xml
<!-- ❌ WRONG - Custom formatter for standard formatting -->
<Text text="{path: 'price', formatter: '.formatCurrency'}"/>

<!-- ✅ CORRECT - Use OData type with format options -->
<Text text="{
    path: 'price',
    type: 'sap.ui.model.odata.type.Decimal',
    formatOptions: {
        style: 'currency',
        currencyCode: 'EUR'
    }
}"/>

<!-- ✅ CORRECT - Use grouping for thousands separator -->
<Text text="{
    path: 'quantity',
    type: 'sap.ui.model.odata.type.Decimal',
    formatOptions: {
        groupingEnabled: true
    }
}"/>
```

**Common OData Types**:
- `sap.ui.model.odata.type.Decimal` - Numbers with decimals
- `sap.ui.model.odata.type.String` - Text with length constraints
- `sap.ui.model.odata.type.DateTime` - Date and time

**Common Simple Types** (use only when no OData equivalent):
- `sap.ui.model.type.DateInterval` - Date ranges
- `sap.ui.model.type.FileSize` - File size formatting

**Example**: For number formatting with thousands separator, prefer `sap.ui.model.odata.type.Decimal` with `formatOptions: {groupingEnabled: true}` over `sap.ui.model.type.Integer` or a custom formatter.

### When to Use Custom Types

Custom types are needed for **special two-way binding scenarios** where built-in types don't provide the required validation or conversion logic.

**Example: Custom Type for Email Validation with Two-Way Binding**

```javascript
// controller/EmailType.js
sap.ui.define(["sap/ui/model/SimpleType"], function(SimpleType) {
    return SimpleType.extend("my.app.type.EmailType", {
        formatValue: function(oValue) {
            return oValue;
        },
        parseValue: function(oValue) {
            return oValue;
        },
        validateValue: function(oValue) {
            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            if (oValue && !emailRegex.test(oValue)) {
                throw new sap.ui.model.ValidateException("Invalid email format");
            }
        }
    });
});
```

**Usage in View**:
```xml
<!-- ❌ WRONG - Formatter doesn't work for two-way binding validation -->
<Input value="{path: 'email', formatter: '.validateEmail'}"/>

<!-- ✅ CORRECT - Custom type enables two-way binding with validation -->
<Input 
    core:require="{EmailType: 'my/app/type/EmailType'}"
    value="{
        path: 'email',
        type: 'EmailType'
    }"/>
```

**Why Custom Types**:
- ✅ Two-way binding support (formatValue + parseValue + validateValue)
- ✅ Real-time validation as user types
- ✅ Model updates immediately on valid input
- ❌ Custom formatters only work for one-way (display) binding


### Data Binding in Views

**ALWAYS** use data binding to connect controls to models:

```xml
<!-- Property binding -->
<Input value="{/customer/name}"/>

<!-- Aggregation binding -->
<List items="{/products}">
    <StandardListItem title="{name}" description="{price}"/>
</List>

<!-- Expression binding -->
<Text text="{= ${quantity} * ${price} }" visible="{= ${stock} > 0 }"/>
```

---

## 4. Internationalization (i18n)

### Translation Workflow Guidelines

When modifying `.properties` files, follow the appropriate workflow based on your project type:

**For development and testing**:
- Update `i18n.properties` (base file) only
- Changes will be reflected immediately for development

**Production translation workflows**:
- **SAP S/4HANA apps**: **NEVER** manually edit localized files (`i18n_de.properties`, `i18n_fr.properties`, etc.)
  - Translation is handled through SAP's internal translation process
- **Apps using SAP Translation Hub or Translation Export/Import (TEW)**: **DO NOT** touch localized files
  - Translations are generated automatically from the base file
- **Manually translated apps only**: Apply changes to all locale files to maintain consistency

**Why**: Professional translation workflows generate localized files from the base `i18n.properties` file. Manual edits to localized files will be overwritten during the translation process.

---

## 5. Security - Content Security Policy

### Never Use Inline Scripts or Styles

**NEVER** use inline scripts or inline styles in HTML. They violate the recommended CSP settings for UI5 applications.

```html
<!-- ❌ WRONG - Violates CSP -->
<script>
    alert("Hello");
</script>

<style>
    .error { color: red; }
</style>

<div style="color: red;">Styled text</div>

<!-- ✅ CORRECT - External files -->
<script src="controller/Main.controller.js"></script>
<link rel="stylesheet" href="css/style.css">

<!-- ✅ CORRECT - CSS classes -->
<div class="errorText">Styled text</div>
```

**Requirements**:
- All application logic must reside in dedicated JS or TS files
- All styling must reside in dedicated CSS files
- Inline `<script>` tags violate CSP
- Inline `<style>` tags violate CSP
- Inline `style` attributes violate CSP

**Reference**: UI5 documentation page "Content Security Policy"

---

## 6. TypeScript Event Handling (UI5 >= 1.115.0)

### Use Control-Specific Event Types

For **UI5 1.115.0 and above**, import and use the specific event type from the control's module.

**Pattern**: `<ControlName>$<EventName>Event` (notice the "Event" suffix)

```typescript
// ✅ CORRECT - Import specific event type
import { Button$PressEvent } from "sap/m/Button";
import { Table$RowSelectionChangeEvent } from "s

Related in Design