What Annotations Actually Do
The list report is metadata-driven. You never build the table, the search, or the columns by hand — you declare them in annotations, and Fiori Elements renders the UI from them. The template reads the OData V4 metadata at runtime and decides what to draw.
Think of annotations as a contract between your data model and the floorplan. The annotation says "this field is a filter, these fields are columns, this field opens the object page" — the template handles everything else.
Where Annotations Live
In a RAP-based service, annotations sit in CDS metadata extension files next to the service definition. In CAP Node.js, they live in annotations.cds files. Either way, they travel inside the OData service metadata, so the app always sees them.
You rarely write raw XML anymore. The ADT annotation modeler in Eclipse or the guided development tools in VS Code generate the XML for you. Still, reading the generated output helps when something does not render the way you expect.
LineItem: The Table Columns
UI.LineItem controls the table. Each record is one column, and the order of the records is the order of the columns on screen. That is the whole story for the table body.
@UI.lineItem: [ { position: 10 },
{ position: 20, importance: #HIGH } ]
SalesOrderID;
@UI.lineItem: [ { position: 30 } ]
CustomerName;
Position decides the column order. Importance decides which columns survive when the table collapses on a phone — mark the columns that actually matter with #HIGH.
Key takeaway: the table is not a control you configure — it is a projection of your UI.LineItem annotation. Fix the annotation, not the UI.
SelectionFields: The Filter Bar
UI.SelectionFields decides which fields appear in the filter bar above the table. Only annotate fields users genuinely filter by. A filter bar with twelve fields helps nobody.
annotate SalesOrder with @UI.selectionFields: [
SalesOrderID,
CustomerName,
OrderStatus
];
Fields you annotate with @Consumption.valueHelpDefinition get a value help dialog in the filter automatically. Combine selection fields with value helps and the filter bar feels like a professional search, because it is.
Identification and HeaderInfo
UI.Identification marks the fields that identify one row — the ones that become the link into the object page. UI.HeaderInfo then controls what the object page shows in its header.
Get these two right early. If the identification field is wrong, users click a row and land on a header that makes no sense. The list report and the object page share these annotations, so one fix improves both.
Common Gotchas
- Column not showing: check that the field is in
UI.LineItem— fields in the entity but not in the annotation never render. - Filter missing: same story with
UI.SelectionFields. The entity having the field is not enough. - Wrong column order: position values are relative, not absolute. Renumber with gaps (10, 20, 30) so inserting a column later does not require renumbering everything.
- Changes not visible: clear the browser cache and reload the app preview. Annotation changes are cached aggressively in metadata.
Debugging rule of thumb: if the UI looks wrong, open the service metadata ($metadata) and check whether the annotation actually arrived. Nine times out of ten, the problem is a missing or misplaced annotation, not a template bug.
Which annotation tripped you up the first time you built a list report? Drop it in the comments.