Skip to main content
Output components are used to display data to users in form responses. The framework provides various output types optimized for different data presentation scenarios.

Component Overview

All output components are defined in the UiMetadataFramework.Basic.Output namespace. Each component has a corresponding C# type that you use in your form response classes.

Purpose

Displays text and boolean values as read-only output.

C# Types

Supports:
  • string
  • bool

Component Type

text

Usage Example

public class MyFormResponse : FormResponse
{
    [OutputField(Label = "User name")]
    public string UserName { get; set; }
    
    [OutputField(Label = "Is active")]
    public bool IsActive { get; set; }
}

Implementation

Defined in StringOutputComponentBinding.cs:
  • Server types: string, bool
  • Component type: "text"
  • Category: Output

Purpose

Displays numeric values as read-only output.

C# Types

Supports multiple numeric types:
  • int
  • decimal
  • double
  • short
  • long
  • byte

Component Type

number

Usage Example

public class MyFormResponse : FormResponse
{
    [OutputField(Label = "Total items")]
    public int TotalItems { get; set; }
    
    [OutputField(Label = "Total price")]
    public decimal TotalPrice { get; set; }
}

Implementation

Defined in NumberOutputComponentBinding.cs:
  • Server types: int, decimal, double, short, long, byte
  • Component type: "number"
  • Category: Output

Purpose

Displays date and time values as read-only output.

C# Type

DateTime

Component Type

datetime

Usage Example

using System;

public class MyFormResponse : FormResponse
{
    [OutputField(Label = "Created at")]
    public DateTime CreatedAt { get; set; }
    
    [OutputField(Label = "Last modified")]
    public DateTime? LastModified { get; set; }
}

Implementation

Defined in DateTimeOutputComponentBinding.cs:
  • Server type: typeof(DateTime)
  • Component type: "datetime"
  • Category: Output

Purpose

Displays a list of actions (links to forms) that the user can perform.

C# Type

ActionList

Component Type

action-list

Usage Example

using UiMetadataFramework.Basic.Output.ActionList;
using UiMetadataFramework.Basic.Output.FormLink;

public class MyFormResponse : FormResponse
{
    [OutputField(Label = "Available actions")]
    public ActionList Actions { get; set; }
}

// In your form handler:
public MyFormResponse Handle(MyFormRequest request)
{
    return new MyFormResponse
    {
        Actions = new ActionList(
            new FormLink
            {
                Form = "edit-user",
                Label = "Edit",
                InputFieldValues = new Dictionary<string, object> { { "userId", request.UserId } }
            },
            new FormLink
            {
                Form = "delete-user",
                Label = "Delete",
                Action = FormLinkActions.Run,
                InputFieldValues = new Dictionary<string, object> { { "userId", request.UserId } }
            }
        )
    };
}

Properties

  • Actions (IList<FormLink>): List of form links

Constructor

public ActionList(params FormLink[] actions)

Implementation

Defined in ActionList.cs:
[MyOutputComponent("action-list")]
public class ActionList
{
    public IList<FormLink> Actions { get; set; }
}

See Also

Purpose

Displays collections of data as a table with automatic column generation.

C# Types

Supports:
  • IEnumerable<T>
  • IList<T>
  • Array

Component Type

table

Usage Example

using System.Collections.Generic;

public class User
{
    [OutputField(Label = "ID")]
    public int Id { get; set; }
    
    [OutputField(Label = "Name")]
    public string Name { get; set; }
    
    [OutputField(Label = "Email")]
    public string Email { get; set; }
    
    [OutputField(Label = "Status")]
    public bool IsActive { get; set; }
}

public class MyFormResponse : FormResponse
{
    [OutputField(Label = "Users")]
    public IEnumerable<User> Users { get; set; }
}

Table Configuration

The table automatically generates columns based on the properties of the item type. Properties decorated with [OutputField] become table columns.Column Generation:
  • Uses OutputField attributes from the item class
  • Supports nested output components
  • Automatically determines appropriate component for each property type

Implementation

Defined in TableOutputComponentBinding.cs:
public class TableOutputComponentBinding : ComponentBinding
{
    public TableOutputComponentBinding() : base(
        MetadataBinder.ComponentCategories.Output,
        [
            typeof(IEnumerable<>),
            typeof(IList<>),
            typeof(Array)
        ],
        "table",
        typeof(TableMetadataFactory))
    {
        this.AdditionalData = new Dictionary<string, object?> 
        { 
            { nameof(MyOutputComponentAttribute.NoLabelByDefault), true } 
        };
    }
}

TableMetadataFactory

The factory automatically extracts column metadata from the item type:
public class TableMetadataFactory : DefaultMetadataFactory
{
    protected override void AugmentConfiguration(
        Type type,
        Type? derivedType,
        MetadataBinder binder,
        ComponentConfigurationAttribute[] configurations,
        Dictionary<string, object?> result)
    {
        var innerType = type.IsArray
            ? type.GetElementType()
            : type.GenericTypeArguments[0];

        result["Columns"] = binder.Outputs.GetFields(innerType).ToList();
    }
}

Notes

  • Tables have no label by default
  • Columns are automatically configured from the item type’s output fields
  • Supports custom output components within table cells

Purpose

Displays large datasets with pagination, sorting, and navigation controls.

C# Type

PaginatedData<T>

Component Type

paginated-data

Usage Example

using UiMetadataFramework.Basic.Inputs.Paginator;
using UiMetadataFramework.Basic.Output.PaginatedData;

public class ListUsersRequest
{
    [InputField(Hidden = true)]
    public Paginator Paginator { get; set; }
}

public class ListUsersResponse : FormResponse
{
    [OutputField]
    [PaginatedData(nameof(ListUsersRequest.Paginator))]
    public PaginatedData<User> Users { get; set; }
}

// In your form handler:
public ListUsersResponse Handle(ListUsersRequest request)
{
    var paginator = request.Paginator ?? new Paginator();
    var pageSize = paginator.PageSize ?? 10;
    var pageIndex = paginator.PageIndex ?? 0;
    
    var query = dbContext.Users.AsQueryable();
    
    // Apply sorting
    if (!string.IsNullOrEmpty(paginator.OrderBy))
    {
        query = paginator.Ascending == true
            ? query.OrderBy(paginator.OrderBy)
            : query.OrderByDescending(paginator.OrderBy);
    }
    
    var totalCount = query.Count();
    var items = query.Skip(pageIndex * pageSize).Take(pageSize).ToList();
    
    return new ListUsersResponse
    {
        Users = new PaginatedData<User>
        {
            Results = items,
            TotalCount = totalCount
        }
    };
}

Properties

  • Results (IEnumerable<T>?): Items for the current page
  • TotalCount (int): Total number of items across all pages

PaginatedDataAttribute

Configures which paginator controls this paginated data.
public class PaginatedDataAttribute : ComponentConfigurationAttribute
{
    public string Paginator { get; }
}
Parameters:
  • paginator: Name of the input field of type Paginator that controls pagination
Usage:
[PaginatedData(nameof(MyFormRequest.Paginator))]
public PaginatedData<User> Users { get; set; }

Paginator

The companion input component that controls pagination. See Paginator in Input Components.Properties:
  • PageIndex (int?): Current page number (0-based)
  • PageSize (int?): Number of items per page
  • OrderBy (string?): Property name to sort by
  • Ascending (bool?): Sort direction

Implementation

Defined in PaginatedData.cs:
[MyOutputComponent("paginated-data", typeof(PaginatedDataMetadataFactory), NoLabelByDefault = true)]
[HasConfiguration(typeof(PaginatedDataAttribute), mandatory: true)]
public class PaginatedData<T>
{
    public IEnumerable<T>? Results { get; set; }
    public int TotalCount { get; set; }
}

Notes

  • No label by default
  • Automatically handles pagination UI on the client
  • Works in conjunction with Paginator input component
  • Supports sorting by any property of the item type

Purpose

Embeds another form directly within the current form’s response. Useful for composing complex UIs.

C# Type

InlineForm

Component Type

inline-form

Usage Example

using UiMetadataFramework.Basic.Output.InlineForm;

public class DashboardResponse : FormResponse
{
    [OutputField(Label = "Quick search")]
    public InlineForm SearchForm { get; set; }
    
    [OutputField(Label = "Recent activity")]
    public InlineForm ActivityForm { get; set; }
}

// In your form handler:
public DashboardResponse Handle(DashboardRequest request)
{
    return new DashboardResponse
    {
        SearchForm = new InlineForm
        {
            Form = "search-users",
            InputFieldValues = new Dictionary<string, object?>
            {
                { "departmentId", request.DepartmentId }
            }
        },
        ActivityForm = new InlineForm
        {
            Form = "recent-activity"
        }
    };
}

Properties

  • Form (string): Name of the form to render inline (required)
  • InputFieldValues (IDictionary<string, object?>?): Pre-populate input fields of the embedded form

Implementation

Defined in InlineForm.cs:
[MyOutputComponent("inline-form")]
public class InlineForm
{
    public string Form { get; set; } = null!;
    public IDictionary<string, object?>? InputFieldValues { get; set; }
}

Use Cases

  • Dashboards: Compose multiple forms into a single view
  • Wizards: Embed sub-forms within a larger workflow
  • Contextual Actions: Show related forms based on current data

Notes

  • The embedded form is fully functional and can be submitted independently
  • Input values can be pre-populated from the parent form’s context
  • The embedded form maintains its own metadata and validation rules

See Also

Build docs developers (and LLMs) love