Fix Control Renderer Issues
This skill fixes Control renderer issues that the UI5 linter detects but cannot auto-fix because they require understanding of the control's rendering behavior and module dependencies.
Linter Rules Handled
When to Use
Apply this skill when you see linter output like:
Background: Why apiVersion: 2?
UI5's rendering framework evolved from an immediate DOM manipulation model (apiVersion 1) to a semantic rendering model (apiVersion 2 and 4). The key differences:
- apiVersion 1 (deprecated): Direct DOM manipulation via
oRm.write(),oRm.writeAttribute(), etc. - apiVersion 2: Semantic methods like
oRm.openStart(),oRm.openEnd(),oRm.text(),oRm.close() - apiVersion 4: Same as 2, with additional performance optimizations (for modern UI5)
Without explicit apiVersion, UI5 assumes legacy rendering which causes synchronous loading and performance issues.
Implicit Renderer Auto-Discovery (Removed in modern UI5)
In UI5 1.x, if a control doesn't declare a renderer property, the framework automatically tries to load a renderer module by appending Renderer to the control's module path. For example, for sap/m/Button, it checks whether sap/m/ButtonRenderer exists — if so, that module is loaded and used as the renderer.
This implicit auto-discovery is removed in modern UI5. Every control must explicitly declare its renderer. If a control relied on auto-discovery and has no renderer property, it will break at runtime. The linter flags this as no-deprecated-control-renderer-declaration with the message "Control '...' is missing a renderer declaration".
The modernization workflow is: check whether a <ControlName>Renderer module exists at the default path → if yes, import it via sap.ui.define → assign it to the renderer property.
Fix Strategy
1. Missing Renderer Declaration
Problem: Control class doesn't declare a renderer at all.
Fix Strategy A - No rendering needed (control is abstract or uses child controls):
Fix Strategy B - Renderer exists in separate file (including implicit auto-discovery):
In UI5 1.x, many controls rely on the framework's implicit auto-discovery — they have no renderer property, but a <ControlName>Renderer.js file exists at the default path and gets loaded automatically. Since this auto-discovery is removed in modern UI5, you need to make the import explicit.
How to find the renderer:
- Derive the expected renderer path: take the control's module path and append
Renderer. Formy/app/control/MyControl, check formy/app/control/MyControlRenderer. - Look for the file in the project (e.g.,
MyControlRenderer.jsin the same directory as the control). - If the renderer file exists, import it and assign it. If it doesn't exist, use Fix Strategy A (
renderer: null) or Fix Strategy C (inline renderer).
Important: After importing the renderer, also check whether the renderer module itself has apiVersion: 2. If not, that's a separate linter finding — see section 3 "Missing apiVersion in Renderer" below.
Fix Strategy C - Add inline renderer:
2. String-Based Renderer Declaration
Problem: Renderer declared as string causes synchronous loading.
Fix Strategy: Import the renderer module and assign directly.
3. Missing apiVersion in Renderer
Problem: Renderer object or function without apiVersion declaration.
Fix Strategy: Add apiVersion: 2 and convert to semantic rendering API.
apiVersion 1 to apiVersion 2 Method Conversions:
For the complete conversion table with examples, read references/renderer-api-mapping.md.
4. Missing IconPool Import
Problem: Using oRm.icon() without importing IconPool.
Fix Strategy: Add IconPool to the imports. The import is required even though it's not directly referenced in code.
5. Deprecated rerender() Override
Problem: Overriding rerender() method no longer works in UI5 1.121+.
Fix Strategy: Move pre-render logic to onBeforeRendering() and post-render logic to onAfterRendering().
Implementation Steps
-
Run linter with --details to get additional context:
-
Identify the error pattern from linter output (rule ID + message)
-
Determine the control's rendering needs:
- Does the control need custom rendering?
- Is there an existing separate renderer file? Check the default path:
<ControlName>Renderer.jsin the same directory (UI5 1.x auto-discovery path) - Does the renderer use
oRm.icon()?
-
Apply the appropriate transformation:
- For missing declaration: Check if
<ControlName>Renderer.jsexists at the default path (auto-discovery). If yes, import and assign it. If no, addrenderer: nullor create an inline renderer - For string declaration: Convert to module import
- For missing apiVersion: Add
apiVersion: 2and convert render methods - For IconPool: Add the import to sap.ui.define dependencies
- For rerender override: Move logic to lifecycle hooks
- For non-static: Add
statickeyword (ES6 classes)
- For missing declaration: Check if
-
Verify the fix by re-running the linter
Example Fix Session
Given linter output:
Before:
After:
Notes
-
Controls that extend these base classes do NOT need a renderer declaration:
sap/ui/core/mvc/Viewsap/ui/core/XMLCompositesap/ui/core/webc/WebComponentsap/uxap/BlockBase
-
apiVersion: 4is also valid and provides additional optimizations for modern UI5 -
When converting from apiVersion 1 to 2, ensure all
write()calls are properly converted to semantic methods -
The IconPool import is needed at module load time for icon font registration, even if
IconPoolvariable is not used in code
Related Skills
- fix-js-globals: For
no-globalserrors in non-renderer JavaScript files (e.g., controllers, utilities), use fix-js-globals — it handlessap.ui.definedependency additions and global access replacement - fix-pseudo-modules: If renderer code also has enum or DataType pseudo module imports, use fix-pseudo-modules for those specific issues
- fix-library-init: For
Library.init()/Lib.init()apiVersion errors ("Deprecated call to ... Use the {apiVersion: 2} parameter"), use fix-library-init — it handles library initialization, not renderer objects

