Add @UI.LineItem, @UI.HeaderInfo, @UI.Facets, @UI.FieldGroup, and value help annotations for Fiori Elements rendering.
@UI.LineItem, @UI.HeaderInfo, @UI.Facets, @UI.FieldGroup@Common.ValueListFiori Elements generates the full UI from annotations — no custom JavaScript needed for standard layouts. Getting these annotations right means the UI builds itself. Getting them wrong means hours debugging why your Object Page has no fields.
CDS Entity → Service Projection → Annotations → Fiori Elements renders UI
Annotations live in the service layer (or a separate .cds file), not on the DB entity.
// srv/annotations.cds
using OrdersService as svc from './orders-service';
annotate svc.Orders with @(
UI.LineItem: [
{ Value: ID, Label: 'Order ID' },
{ Value: buyer.name, Label: 'Buyer' },
{ Value: status, Label: 'Status' },
{ Value: total, Label: 'Total' },
{ Value: createdAt, Label: 'Created' },
{
$Type: 'UI.DataFieldForAction',
Action: 'OrdersService.submitOrder',
Label: 'Submit'
}
],
UI.SelectionFields: [ status, createdAt, buyer_ID ],
UI.PresentationVariant: {
SortOrder: [{ Property: createdAt, Descending: true }]
}
);
annotate svc.Orders with @(
UI.HeaderInfo: {
TypeName: 'Order',
TypeNamePlural: 'Orders',
Title: { Value: ID },
Description: { Value: buyer.name }
}
);
annotate svc.Orders with @(
UI.Facets: [
{
$Type: 'UI.ReferenceFacet',
ID: 'GeneralInfo',
Label: 'General Information',
Target: '@UI.FieldGroup#GeneralInfo'
},
{
$Type: 'UI.ReferenceFacet',
ID: 'Items',
Label: 'Order Items',
Target: 'items/@UI.LineItem'
}
],
UI.FieldGroup#GeneralInfo: {
Data: [
{ Value: status, Label: 'Status' },
{ Value: total, Label: 'Total Amount' },
{ Value: notes, Label: 'Notes' },
{ Value: createdAt, Label: 'Created At' }
]
}
);
// Enum-based value help from a Currencies entity
annotate svc.Orders with {
currency @(
Common.ValueList: {
CollectionPath: 'Currencies',
Parameters: [
{ $Type: 'Common.ValueListParameterOut', LocalDataProperty: currency_code, ValueListProperty: 'code' },
{ $Type: 'Common.ValueListParameterDisplayOnly', ValueListProperty: 'name' }
]
},
Common.ValueListWithFixedValues: true
)
}
annotate svc.Orders with {
statusCriticality @UI.Hidden; // used internally, not shown as column
}
annotate svc.Orders with @(
UI.LineItem: [
{
Value: status,
Criticality: statusCriticality // 1=grey, 2=red, 3=orange, 4=green
}
]
);
// Computed in AFTER handler
this.after('READ', 'Orders', (orders) => {
orders.forEach(o => {
o.statusCriticality = { DRAFT: 0, SUBMITTED: 2, SHIPPED: 3, DELIVERED: 4 }[o.status] ?? 0
})
})
annotate svc.OrderItems with @(
UI.LineItem: [
{ Value: book.title, Label: 'Book' },
{ Value: quantity, Label: 'Quantity' },
{ Value: price, Label: 'Price' }
]
);
srv/
├── orders-service.cds ← service definition
├── orders-service.js ← handlers
└── fiori/
├── orders-annotations.cds ← Fiori annotations
└── catalog-annotations.cds
// srv/fiori/orders-annotations.cds
using OrdersService as svc from '../orders-service';
// all @UI, @Common, @Communication annotations here
@UI.LineItem (title, author, price, stock)@UI.HeaderInfo with title=title, description=author_namegenre from a Genres entitycds watch and verify the layout@UI.LineItem drives the list report columns@UI.Facets + @UI.FieldGroup build the Object Page sections@Common.ValueList with CollectionPath