AI agents: the content index is at /llms.txt. Every page is also available as Markdown — send the request header Accept: text/markdown, or append .md to the page URL.
Xperience Docs

Cookie consent

We use necessary cookies (opens in a new tab) to run our website and improve your experience while browsing. Additional cookies are only used with your consent. You may revoke your consent on the Cookies Policy (opens in a new tab) page or in your browser at any time.

Configure (opens in a new tab)
  • Documentation
    Administration interface basicsDevelopers and adminsBusiness usersChangelogGlossary
  • Guides
    Welcome to Xperience by KenticoAdministration interface basicsCustomer journeysDigital marketingConfigurationDevelopmentArchitectureUpgrade to Xperience by Kentico
  • Training
    For AdminsFor Business usersFor DevelopersFor Solution architects
  • API Examples
    ConfigurationContent managementDevelopmentDigital marketing
  • Changelog
    Documentation updatesSecurity advisories
  • Community Questions & Answers (opens in a new tab)
  • Contact support (opens in a new tab)
  1. Home
  2. Developers and admins
  3. Customization
  4. Extend the administration interface
  5. UI pages
  6. Reference - UI page templates
  7. Listing UI page template
  8. Add listing actions

Add listing actions


Was this page helpful?

Send us feedback Go back to top

Listing pages can invoke page commands from individual rows, from the page header, and over multiple items selected by the user at once. Add the actions within an override of the ConfigurePage method, either on the listing page itself or on its page extender.

Add row actions

The listing template allows you to assign a page command that gets invoked when users select a row in the listing.

A typical use case for this is opening an item's view or edit page (e.g., for users, contacts). For this purpose, the system provides the PageConfiguration.AddEditRowAction<TInfoEditPage> extension method. The method generates a link to an edit page for each item (by ensuring the corresponding object's ID in the URL). Specify the System.Type of the corresponding edit layout page as the method's generic parameter.

See the Page URLs and routing section on UI pages for more information about generating URL structures for admin pages.

Add header and item actions

The listing page allows you to add actions (page commands) to the page header (displayed to the left of the search box) and to each item in the grid (displayed in the Actions column).

Add actions to the listing by calling the following methods on either PageConfiguration.HeaderActions or PageConfiguration.TableActions:

  • AddDeleteAction – adds a delete action to individual items in the list. The base class provides a Delete page command that deletes items based on an object's ID.

    C#Delete page command provided by the ListingPage base class
    [PageCommand]
    public override Task<ICommandResponse<RowActionResult>> Delete(int id) => base.Delete(id);
  • AddLink<TPage> – adds a link to a specified page in the admin UI. Supply the System.Type of the target page as the method's generic parameter.

  • AddCommand – adds a page command to the page header or an item's Actions column.

  • AddCommandWithConfirmation – adds a page command in exactly the same way as AddCommand, but guarantees that users are asked to confirm the action before the command is invoked. Both methods accept the same parameters and place the same requirements on the command's handler.

Commands are referenced by the name of their handler method, not by a delegate. Pass nameof(YourHandler) as the commandName parameter and implement the handler on the listing page class (or on its page extender), annotated with the PageCommand attribute.

The required handler signature depends on where the action is displayed:

  • Item actions (added to PageConfiguration.TableActions) are invoked for a single listed item. The system passes the identifier of the row whose action was selected (the value of the listed object type's ID column) to the handler. The handler returns ICommandResponse<RowActionResult>, which instructs the client what to refresh once the command finishes.

    C#Item action handler signature
    [PageCommand]
    public async Task<ICommandResponse<RowActionResult>> MyItemAction(int id, CancellationToken cancellationToken)
  • Header actions (added to PageConfiguration.HeaderActions) are not bound to any listed item and therefore receive no identifier. Header actions are rendered as standalone buttons that do not evaluate RowActionResult, so their handlers return the general ICommandResponse.

    C#Header action handler signature
    [PageCommand]
    public async Task<ICommandResponse> MyHeaderAction(CancellationToken cancellationToken)

Apart from an optional CancellationToken parameter and an optional confirmation model parameter, command handlers can declare at most one parameter, which receives the data sent with the command. You can declare the parameters in any order.

Set the PageCommand attribute's Permission property to require a permission for the action's invocation.

C#
[PageCommand(Permission = SystemPermissions.UPDATE)]

Implement command actions

Actions can either invoke a page command that the ListingPage base class already implements, as AddDeleteAction does with the Delete command, or a command you implement yourself. To implement your own, declare a handler annotated with the PageCommand attribute and reference it from AddCommand or AddCommandWithConfirmation.

Item action handlers construct their ICommandResponse<RowActionResult> using the ResponseFrom method, which is available both on listing pages and on page extenders. You can optionally chain the message extension methods described under UI page commands.

C#
return ResponseFrom(new RowActionResult(reload: true))
            .AddSuccessMessage("The item was updated.");

RowActionResult instructs the client what to refresh once the command finishes. Both of its properties are read-only and set via the constructor:

Parameter

Description

reload

Reloads the data of the listing's table – the system re-executes the listing's data query and re-renders the grid, including the action state evaluators of all rows. Set to true whenever the command changes data displayed in the listing.

Set to false when the listing's content is unaffected by the command (for example, when the command only sends an email, or when it failed and made no changes). The grid keeps displaying the data it loaded before the action was invoked.

refetchAll

Re-fetches the data of all UI page templates currently rendered on the page, not just the listing's table. Use it when the command changes state displayed outside of the listing itself, for example a counter in a parent template, a header, or a sidebar.

Because the listing template is one of the re-fetched templates, its data is reloaded as well. refetchAll therefore takes precedence over reload, and setting both to true has the same effect as setting refetchAll alone.

Defaults to false. Prefer reload unless the action's impact reaches outside the listing – re-fetching all templates is significantly more expensive.

The reload and refetchAll flags are only processed for actions in PageConfiguration.TableActions and PageConfiguration.MassActions. Actions in PageConfiguration.HeaderActions do not evaluate the returned result. To refresh the page after a header action, return NavigateTo(url, refetchAllTemplates: true) instead, where url is the path of the page to display (for example, the listing's own path obtained from IPageLinkGenerator).

Example – custom item action

The following example adds a Disable action to each item of a listing of MemberInfo objects. The example assumes an IInfoProvider<MemberInfo> service retrieved into the memberProvider field via dependency injection.

C#Adding and handling a custom item action
using System.Threading.Tasks;

using CMS.DataEngine;
using CMS.Membership;

using Kentico.Xperience.Admin.Base;

// ...
// Declaration of the containing class and the 'IInfoProvider<MemberInfo> memberProvider' field
// ...

public override Task ConfigurePage()
{
    PageConfiguration.TableActions
        // References the 'Disable' page command by its name
        .AddCommand(new AddCommandParameters(commandName: nameof(Disable), label: "Disable")
        {
            Icon = Icons.Lock,
            Title = "Prevent the member from signing in"
        });

    return base.ConfigurePage();
}


// Handles the 'Disable' action. The system binds the identifier of the row
// whose action was invoked to the 'id' parameter.
[PageCommand(Permission = SystemPermissions.UPDATE)]
public Task<ICommandResponse<RowActionResult>> Disable(int id)
{
    var member = memberProvider.Get(id);

    if (member is null)
    {
        // The listing is out of sync with the database - reloads it to reflect the current state
        return Task.FromResult(ResponseFrom(new RowActionResult(reload: true))
                    .AddErrorMessage("The member no longer exists."));
    }

    member.MemberEnabled = false;
    memberProvider.Set(member);

    // Reloads the listing's data, which displays the member's new state.
    // 'refetchAll' is not needed - the change is contained within this listing.
    return Task.FromResult(ResponseFrom(new RowActionResult(reload: true))
                .AddSuccessMessage($"'{member.MemberName}' was disabled."));
}

Declare both members either directly on the listing page class, or on a page extender of the listing page. Page extenders access the listing's configuration through their Page property – use Page.PageConfiguration.TableActions instead of PageConfiguration.TableActions.

To run custom logic over multiple items at once, add a mass action instead.

Raise a confirmation prompt

You can optionally display a confirmation dialog when users select an action or link. Call the AddCommandWithConfirmation or AddLinkWithConfirmation<TPage> methods.

AddCommandWithConfirmation accepts the same parameters as AddCommand and requires the same command handler. The two methods only differ in how they behave when ConfirmationParameters are not set – AddCommandWithConfirmation falls back to a generic confirmation dialog, while AddCommand invokes the command without prompting the user. Setting ConfirmationParameters therefore raises a confirmation dialog with either method.

C#Raise a confirmation prompt on command invocation
public override Task ConfigurePage()
{
    PageConfiguration
        .TableActions
            .AddCommandWithConfirmation
                (
                    new AddCommandParameters(commandName: nameof(DoSomething), label: "Title")
                    {
                        Icon = Icons.ArrowsCrooked,
                        Title = "Text of the tooltip.",
                        // Providing these properties raises a confirmation dialog
                        // when a user invokes the corresponding action
                        ConfirmationParameters = new ConfirmationWithContentParameters
                        {
                            Confirmation = "What do you want to do?",
                            ConfirmationButton = "This, please",
                        }
                    });

    return base.ConfigurePage();
}

When users invoke the action, they are prompted with the following confirmation.

Additionally, the dialog can also display a form that allows users to submit data to the corresponding command handler. For example, this can be a multiple-choice selector that determines how the back end processes the action.

The form must be defined within a dedicated model class and annotated with Editing components. Validation rules are also supported. The class must be annotated with CommandConfirmationModel.

C#Model defining the confirmation form
[CommandConfirmationModel]
public class ConfirmationDialogFormModel
{
    [RequiredValidationRule]
    [RadioGroupComponent(Inline = false, Order = 1,
                         Options = "option1;Option 1\r\noption2;Option 2\r\n")]
    public string ChooseOne { get; set; } = "option1";
}

Specify the model class as a parameter within AddCommandWithConfirmation. The other parameters of the method are identical to AddCommand.

C#Raise a confirmation prompt on command invocation
public override Task ConfigurePage()
{
    PageConfiguration
        .TableActions
            .AddCommandWithConfirmation
                (
                    new AddCommandParameters(commandName: nameof(DoSomething), label: "Title")
                    {
                        Icon = Icons.ArrowsCrooked,
                        Title = "Text of the tooltip.",
                        // Providing these properties raises a confirmation dialog
                        // when a user invokes the corresponding action
                        ConfirmationParameters = new ConfirmationWithContentParameters
                        {
                            Confirmation = "What do you want to do?",
                            ConfirmationButton = "This, please",
                            // Setting the confirmation model displays a dialog with form
                            ConfirmationModel = typeof(ConfirmationDialogFormModel)
                        }
                    });

    return base.ConfigurePage();
}

The corresponding command handler method must expect the form model in its signature. The system automatically binds the form received from the client to the corresponding parameter.

C#Action command handler
[PageCommand]
public Task<ICommandResponse<RowActionResult>> ActionWithFormConfirmation(ConfirmationDialogFormModel model)
{
    // Decide what to do based on the received form data...

    return Task.FromResult(ResponseFrom(new RowActionResult(reload: true))
                 .AddSuccessMessage($"You have selected {model.ChooseOne}"));
}

actionStateEvaluator

Some methods optionally take an Action delegate that allows you to programmatically disable or modify the commands they add for items meeting your specified criteria.

C#Example - disable the delete action for specific users
.AddDeleteAction(
    new AddDeleteActionParameters(commandName: nameof(Delete))
    {
        ActionStateEvaluator = DisableDeleteForSpecificUsers,
    });

// ...

// Disables the delete action for the default global administrator and public users
private Task DisableDeleteForSpecificUsers(ActionConfiguration actionConfiguration, IDataContainer rowData, CancellationToken cancellationToken)
{
    if (!actionConfiguration.Disabled)
    {
        var userName = Convert.ToString(rowData[nameof(UserInfo.UserName)]);

        if (String.Equals(userName, UserInfoProvider.AdministratorUserName, StringComparison.OrdinalIgnoreCase) ||
            String.Equals(userName, UserInfoProvider.PublicUserName, StringComparison.OrdinalIgnoreCase))
        {
            actionConfiguration.Disabled = true;
        }
    }
    return Task.CompletedTask;
}

Add mass actions

The listing page template allows you to add actions executed upon a collection of items selected from the listing.

Mass actions appear at the top of the listing, immediately below the search bar, when users select at least one listed item.

Page commands that implement mass actions must use the following signature:

C#Mass action method signature
public async Task<ICommandResponse<MassActionResult>> MassActionCommand(IEnumerable<int> identifiers, CancellationToken cancellationToken)

where IEnumerable<int> identifiers is a collection of object type IDs identifying the items selected by the user. Use conventional provider APIs to work with these objects.

Add mass actions using the following methods on PageConfiguration.MassActions:

  • AddCommand – adds a command to execute.
  • AddCommandWithConfirmation – adds a command with execution approved via a confirmation prompt.
  • AddActionWithCustomComponent – adds an action that is handled by a custom React component.

Note that the actionStateEvaluator parameter offered by these methods is not supported by mass actions.

C#Register mass actions
public override Task ConfigurePage()
{
    PageConfiguration
        .MassActions
            .AddCommandWithConfirmation
            (
                label: "Title",
                command: nameof(MyMassActionPageCommand),
                icon: Icons.ArrowsCrooked,
                // Providing these properties raises a confirmation
                // dialog when users invoke the added action
                confirmation: "Confirmation title",
                confirmationButton: "Confirm"
            );

    return base.ConfigurePage();
}

Add actions handled by a React component

For advanced action scenarios, you can use a custom React component to handle:

  • Item and header actions (PageConfiguration.TableActions, and PageConfiguration.HeaderActions)
  • Mass actions (PageConfiguration.MassActions)

on listing templates.

Start by preparing the React component's front end (e.g., a .tsx file). The name of the component must end with the Component suffix, e.g., @acme/web-admin/CustomActionComponent. Ensure that the component is exported in your custom admin module's entry.tsx file.

In addition, you also need to create the following back-end classes for each action component:

  • Component class inheriting from ActionComponent<TProperties, TClientProperties>.
    • Override the ClientComponentName property, and set the value to the name of the corresponding front-end component. The Component suffix is automatically added to this name when loading the component.
    • Override the ConfigureClientProperties method to populate the component's client properties (typically from the value of the corresponding back-end properties class).
  • Back-end properties class implementing IActionComponentProperties.
  • Client properties class implementing IActionComponentClientProperties.
C#Custom action component
public sealed class CustomActionComponent : ActionComponent<CustomActionProperties, CustomActionClientProperties>
{
    // The name of the front-end type implementing the action component without the "Component" suffix,
    // which is automatically added to this name.
    public override string ClientComponentName => "@acme/web-admin/CustomAction";
    
    protected override Task ConfigureClientProperties(CustomActionClientProperties clientProperties)
    {
        clientProperties.MyProperty = Properties.MyProperty;
        // ...

        return base.ConfigureClientProperties(clientProperties);
    }
}

To add the action in the listing template configuration, call AddActionWithCustomComponent on the appropriate action collection (e.g., TableActions or MassActions).

Permissions and custom component actions

If you wish to implement permission checks for actions handled by a custom component, we recommend setting the AddActionWithCustomComponent method's disabled parameter (see the example below). You can also propagate permission information to your component via members of the client properties class.

C#Register a mass action with a custom component
private readonly IUIPermissionEvaluator uiPermissionEvaluator;

// ...

public override async Task ConfigurePage()
{
    bool userHasPermission = await UserHasUpdatePermission();

    PageConfiguration.MassActions.AddActionWithCustomComponent(
        clientComponent: new CustomActionComponent() 
        {
            Properties = new CustomActionProperties()
            {
                MyProperty = "MyValue"
            }
        },
        label: "Title",
        icon: Icons.PaperPlane,
        disabled: !userHasPermission
    );

    await base.ConfigurePage();
}

private async Task<bool> UserHasUpdatePermission()
{
    return (await uiPermissionEvaluator.Evaluate(SystemPermissions.UPDATE)).Succeeded;
}

On this page

  • Add row actions
  • Add header and item actions
    • Implement command actions
    • Raise a confirmation prompt
    • actionStateEvaluator
  • Add mass actions
  • Add actions handled by a React component