Display Data in a List
At the end of the previous article, you fetched data from the emulated backend and displayed it as a JSON structure to test the backend. In this article, you will learn how to use data-aware components to display data.
You can continue working with the code you completed in the previous tutorial section. Alternatively, you can download the code from here and carry on.
Fetching Data from API
With XMLUI, fetching data from a REST API is straightforward.
The markup in the previous articles fetched a message with the DataSource
component. Often, you use only a URL to access data in a backend.
When using the data
property (with any component), the framework infers from its value that it must fetch data (invoking a GET request with the particular URL).
To see how it works, replace the Page
tag with the /contacts
URL to use the following contents:
<!-- Omitted -->
<Page url="/contacts">
<List data="/api/contacts" />
</Page>
<!-- Omitted -->
List
is a component that works with an array of items. The framework fetches the data from the /api/contacts
URL and injects it into the List
, which displays each item.
If the app is not running yet, start it on your web server and visit the app's page in your browser. The code snippet you have just added displays some contact data when you click the Contacts menu:

The List
component does not know anything about the semantics and structure of the data. Unless you provide some hints (or a sophisticated description) of the UI to display a particular data item, List
will display a simple layout selecting a field as a title and another as a subtitle.
The default layout is good for quick prototyping, but in this case, you need a better way to display fetched data!
Customizing the List
The List
component is versatile and provides several services, making it easy to customize the layout. In this section, you will change the outlook of list items. A contact record has these fields (columns):
Field | Type | Description |
---|---|---|
id | integer | The unique identifier of the contact |
fullName | string | The contact's name |
categoryId | integer | Reference to the category ID of the contact |
comments | string | Additional information about the contact |
reviewDueDate | date | The date when the contact should be reviewed |
reviewCompleted | boolean | Indicates whether the review is completed |
The default display of the list uses the fullName
and then categoryId
fields. If you want to change the default view of an item, you can modify the template used to show a particular item. Modify the List
component's definition to use a different template:
<!-- Omitted -->
<List data="/api/contacts">
<Card title="{$item.fullName}" subtitle="{$item.comments}" />
</List>
<!-- Omitted -->
The nested markup defines the UI for a single item in the list. The code snippet uses a Card
component for a list item. Card
is a simple container for displaying cohesive data, such as record fields. This component has a predefined layout we can leverage through the title
and subtitle
fields.
When processing the data, List
uses a special property, $item
, to refer to the current iteration item. In the expressions above, $item.fullName
and $item.comments
are the fields of the current iteration item, of a contact record.

Adding and Formatting Fields
Let's change the layout of the items to something more attractive and helpful. Modify the nested items of List
as in the following code snippet:
<!-- Omitted -->
<List data="/api/contacts">
<Card>
<HStack verticalAlignment="center">
<Checkbox initialValue="{$item.reviewCompleted}" />
<VStack width="*" gap="0">
<Text variant="strong">{$item.fullName}</Text>
<Text>{$item.comments}</Text>
</VStack>
<HStack verticalAlignment="center" horizontalAlignment="end">
<Text>{smartFormatDate($item.reviewDueDate)}</Text>
</HStack>
</HStack>
</Card>
</List>
<!-- Omitted -->
Here, you add a checkbox indicating the completeness of a particular item. With the help of VStack
and HStack
layout components, you align the item's title and description in a column with two rows and display the reviewDueDate
field aligned right in the item's row. Observe the smartFormatDate($item.reviewDueDate)
expression, which smartly transforms a reviewDueDate
field, for example, recognizing that a particular date is Yesterday
.

It might occur to you that rendering hundreds or thousands of data items would consume a lot of resources. The List
component is a virtualized container that ensures that only data items visible in the current viewport (and a few near the edges) are rendered.
Categorizing Data
In the app's database, each contact can be assigned a category. The available categories are stored in the database with the following structure:
Field | Type | Description |
---|---|---|
id | integer | The unique identifier of the category |
name | string | The category's name |
color | string | The category's color |
XMLUI has a Badge
component that can use a color map (name and color pairs). When you pass a value to a Badge
, it leverages the color map to set up the component's background according to the badge's text. In this section, you will add a Badge
displaying the category associated with a particular contact:
- Add a
DataSource
component to the markup before theNavPanel
tag with thecategories
identifier. ThisDataSource
component will fetch all category data from the backend.
<App
layout="vertical-sticky"
name="Contact List Tutorial"
logo="resources/logo.svg"
logo-dark="resources/logo-dark.svg">
<AppHeader>
<H2>Contact Management</H2>
<SpaceFiller />
<ToneChangerButton />
</AppHeader>
<DataSource id="categories" url="/api/categories" />
<!-- Omitted -->
<NavPanel>
<!-- Omitted -->
</App>
- Create a new
Main.xmlui.xs
file in the app's root folder. This file intentionally has the same name extended with.xs
as theMain.xmlui
markup file. It is a code-behind file containing variables and functions visible within the app's main component. A code-behind file represents states, actions, and other utility functionality. In this case, it will declare variables. Copy this content into the new file:
// Create a color map for all categories
var categoriesColorMap = toHashObject(categories.value, "name", "color");
// Resolve category name by id
function getCategoryNameById(categoryId) {
const category = findByField(categories.value, "id", categoryId);
return category ? category.name : "";
}
The categoriesColorMap
variable converts the list of topic records into a hash object with the topic name and color value pairs.
The getCategoryNameById
looks up the name of a particular category based on its id.
This transformation with the toHashObject
JavaScript function converts category records from this format
[
{ "name": "<name1>", "color": "<color1>" },
{ "name": "<name2>", "color": "<color2>" },
// ...
]
into a hash object:
{
"<name1>": "<color1>",
"<name2>": "<color2>",
// ...
}
- Change the definition of
Card
within the list:
<!-- Omitted -->
<List data="/api/contacts">
<Card var.categoryName="{getCategoryNameById($item.categoryId)}">
<HStack verticalAlignment="center">
<Checkbox initialValue="{$item.reviewCompleted}" />
<VStack width="*" gap="0">
<Text variant="strong">{$item.fullName}</Text>
<Text>{$item.comments}</Text>
</VStack>
<HStack verticalAlignment="center" horizontalAlignment="end">
<Badge when="{categoryName}" value="{categoryName}" colorMap="{categoriesColorMap}"/>
<Text>{smartFormatDate($item.reviewDueDate)}</Text>
</HStack>
</HStack>
</Card>
</List>
<!-- Omitted -->
This code snippet adds a categoryName
variable to the Card
(this variable's scope is Card
and its children). The markup uses this variable as its value will be used in multiple properties within Badge
; the variable caches the value. The Badge
component uses the categoryName
variable's value to display its text with the associated categoriesColorMap
(maps each category name to a particular color). Observe the when
attribute: if there is no name for the particular contact category, the when
value will be false, and the Badge
component will not be rendered.
Now, running the app will display the topics of task items:

In the following article, you will learn to display filtered data.