---
title: Display and format listing data
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

The [listing page](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/ui-pages/reference-ui-page-templates/listing-ui-page-template.md) displays items of the selected object type in a grid-like structure, one item per line, and one [field](https://docs.kentico.com/documentation/developers-and-admins/customization/field-editor.md) (database column) per column. This page describes how to configure the grid's columns and the elements displayed around it.

## Format displayed data

Specify the displayed item properties within an override of the `ConfigurePage` method. Call the `AddColumn` method on `PageConfiguration.ColumnConfigurations` and provide the name of the database column to be displayed.

```csharp title="Example - adding object properties (database columns) to the grid"
public override Task ConfigurePage()
{
    // Adds the specified columns to the grid and sets their caption
    PageConfiguration.ColumnConfigurations
                // Adds data from the 'UserName', 'FirstName', and 'Email' columns of the 'CMS_User' table
                .AddColumn(nameof(UserInfo.UserName), "User name")
                .AddColumn(nameof(UserInfo.FirstName), "First name")
                .AddColumn(nameof(UserInfo.Email), "Email");

    return base.ConfigurePage();
}
```

You can further configure each column by supplying the following optional parameters to the `AddColumn` method:

- **Caption** – sets a custom caption for the column heading. Defaults to the column name if not set.
- **Sortable** – indicates whether the column can be used to sort the listing.
- **DefaultSortDirection** – a `SortTypeEnum` value that determines the default order for properties in the column.
- **Formatter** – sets the [formatter](https://docs.microsoft.com/en-us/dotnet/api/system.string.format) to use for the column values.

  ```csharp title="Example"
  .AddColumn(nameof(UserInfo.UserCreated), formatter: (value, _) => String.Format("{0:MMMM dd, yyyy}", Convert.ToDateTime(value)))
  ```
- **Visible** – default visibility state of the column. For hidden columns, the data is obtained from the server but hidden.
- **Searchable** – indicates whether column values are searchable via a search box above the listing. If no columns are set as searchable, the search dialog is hidden.
- **Localizable** – persisted values have localization macros resolved.
- **Tooltip** – sets the tooltip for the column.

## Add React components to cells

The listing template supports loading React components inside dedicated columns within the grid via the `AddComponentColumn` extension method of the `PageConfiguration.ColumnConfigurations` object.

The method takes identical parameters as [AddColumn](#format-displayed-data), with the following additions:

- **string componentKey** – the name of the React component to be displayed. Provide a full name in the _{orgName}/{projectName}/component_ format, as specified when you [set up your custom admin JS module](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/prepare-your-environment-for-admin-development.md). Make sure the component is exported (visible to other modules). For example: _@acme/web-admin-custom/MyComponent_.

  > **Note:** **Component naming**
  >
  > When loading the component, the client application suffixes the provided value with `TableCellComponent`. For the provided example, the client React component must be named `MyComponentTableCellComponent`.
- **bool loadedExternally** – indicates whether data present in the column is loaded externally (not a property of the _\*Info_ object being listed). For example, via a separate [ObjectQuery call](https://docs.kentico.com/documentation/developers-and-admins/api/objectquery-api.md) from a different object.
- **Func modelRetriever** – a function that provides the props for the front-end component to be displayed. The component props data must be wrapped in a dedicated class (for serialization and transfer to the client admin application).
  - **object** – the localized (if localizable) and formatted (if a formatter was provided) value of the column to be listed. Empty if the `loadedExternally` flag is `true`.
  - **IDataContainer** – contains the entire database record of the object being listed (as `IDataContainer`). Column values can be accessed using indexer notation.

The system instantiates the selected component for each row, with the passed props.

```csharp title="Example"
protected override string ObjectType => UserInfo.OBJECT_TYPE;

// ...

public override Task ConfigurePage()
{
    PageConfiguration.ColumnConfigurations
        // Adds a column displaying a React component with data loaded from UserInfo
        .AddComponentColumn(
            "assignedRoles",

            // Sets the name of the component to render
            // When loading the component, the client application automatically suffixes
            // the component name with 'TableCellComponent'. For this example, the React
            // component must be named 'MyComponentTableCellComponent'.
            "@orgName/projectName/MyComponent",

            // Sets column caption
            "Roles",

            modelRetriever: (formattedColumnValue, rowData) =>
            {
                // 'formattedColumnValue' contains the localized (if localizable) and
                // formatted (if a formatter was provided) value of the column
                // specified in 'columnName.'
                // Empty if the loadedExternally flag is set to 'true'

                // 'rowData' contains the entire user record
                // from the database (as 'IDataContainer').
                // Column values can be accessed using indexer notation.
                var userID = (int)rowData[nameof(UserInfo.UserID)];

                // Fetches roles assigned to individual users using external logic
                // (omitted for brevity).
                var userRoles = GetRoles(userID);

                // Instantiates a DTO consisting of props for the displayed component
                return new ReactComponentToDisplayProps
                {
                    prop1 = userRoles.ToString(),
                    prop2 = userID
                };
            },

            // Column data will not be fetched as part of the
            // ObjectQuery retrieving other UserInfo object data
            loadedExternally: true,
            sortable: false);

    return base.ConfigurePage();
}
```

If the listing offers [data export](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/ui-pages/reference-ui-page-templates/listing-ui-page-template/export-listing-data.md), register a [cell value extractor](https://docs.kentico.com/documentation/developers-and-admins/customization/extend-the-administration-interface/ui-pages/reference-ui-page-templates/listing-ui-page-template/export-listing-data.md#export-values-of-cells-rendered-by-react-components) for the component to export the value it displays instead of the stored column value.

## Add header subcaption

You can render arbitrary React components next to the listing page caption via `PageConfiguration.SubcaptionComponent`.

![Listing page header subcaption](https://docs.kentico.com/docsassets/documentation/display-and-format-listing-data/listingSubcaption.png "Listing page header subcaption")

The following example demonstrates the required configuration:

```csharp title="Add a subcaption component"
public override Task ConfigurePage()
{
    PageConfiguration.SubcaptionComponent = new MySubcaption
    {
        ComponentProperties = new MySubcaptionProperties
        {
            Label = "...",
            TooltipText = "..."
        },
    };

    return base.ConfigurePage();
}
```

Where `MySubcaption` describes the component to render and is defined as follows:

```csharp
using System.Threading.Tasks;
using Kentico.Xperience.Admin.Base;

// Classes defining subcaption components must inherit from `SubcaptionComponentBase`.
// The two generics describe classes encapsulating the target component's properties on the back-end
// and in the client application. See their definitions below.
public class MySubcaption : SubcaptionComponentBase<MySubcaptionProperties, MySubcaptionClientProperties>
{
    // The full name of the React component to render as the subcaption.
    // This example targets a custom `MySubcaptionComponent` in the web-admin module.
    // You can also use default Xperience components. For example: '@kentico/xperience-admin-components/TextWithLabel'
    public override string ComponentName => "@acme/web-admin/MySubcaptionComponent";

    // Populates the properties used to instantiate the React component on the client
    // Property names must correspond to the properties of the client component
    protected override Task ConfigureComponentClientProperties(MySubcaptionClientProperties componentClientProperties)
    {
        componentClientProperties.Label = ComponentProperties.Label;
        componentClientProperties.TooltipText = ComponentProperties.TooltipText;

        return base.ConfigureComponentClientProperties(componentClientProperties);
    }
}

// Encapsulates the properties of the subcaption component's back-end definition.
// Populated via `PageConfiguration.SubcaptionComponent`. Mapped to 'MySubcaptionClientProperties' 
// within the subcaption class ('MySubcaption' in this example).
public class MySubcaptionProperties
{
    public string Label { get; set; }
    public string TooltipText { get; set; }
}

// Encapsulates properties sent to the client. Used when instantiating the targeted React component.
public class MySubcaptionClientProperties
{
    public string Label { get; set; }
    public string TooltipText { get; set; }
}
```

## Add callouts

Callouts are information messages that can be displayed above the listing grid.

![Callout example](https://docs.kentico.com/docsassets/documentation/display-and-format-listing-data/ListingPageCallout.png "Callout example")

You can add a callout via `PageConfiguration.Callouts`.

```csharp title="Example - adding a callout"
public override Task ConfigurePage()
{
    PageConfiguration.Callouts = new List<CalloutConfiguration>()
    {
        new CalloutConfiguration
        {
            Headline = "Callout headline",
            Content = "Callout text",
            Type = CalloutType.QuickTip,
            Placement = CalloutPlacement.OnDesk
        }
    };

    return base.ConfigurePage();
}
```

Where `CalloutType` determines the style of the callout:

- **QuickTip** – a light blue unobtrusive design intended for general information messages
- **FriendlyWarning** – tinted yellow, designed to attract user attention

And `CalloutPlacement` determines the callout element width:

- **OnDesk** – half-page width
- **OnPaper** – full-page width
