Details

Displays labelled read-only values, such as the fields of a record or its audit information

<sa-details columns="2">
    <sa-display-field asp-for="Reference" />
    <sa-display-field asp-for="Status" />
    <sa-display-field asp-for="LeadTraveller" />
    <sa-display-field asp-for="Email" />
    <sa-display-field asp-for="Destination" href="#destination-@Model.DestinationId" />
    <sa-display-field asp-for="Departure" />
    <sa-display-field asp-for="Party" />
    <sa-display-field asp-for="Total" />
    <sa-display-field asp-for="PromoCode" />
</sa-details>

Usage

A details list is composed of <sa-details> wrapping one <sa-display-field> per value. Bind each field to a model property with asp-for: the label comes from the property's [Display] name, and the value is formatted from the property's metadata.

<sa-details columns="...">
    <sa-display-field asp-for="..." />
    <sa-display-field asp-for="..." />
</sa-details>

Inside <sa-details> the fields render as a description list, with each label in a <dt> and each value in a <dd>. A <sa-display-field> can also be used on its own, for example among the inputs of a form; it then renders <div> elements instead.

Examples

Columns and spans

Set columns to lay the fields out in a grid. The columns respond to the width of the list rather than the viewport, so the same markup works in a page, a card or a side panel. columns applies once the list is at least 40rem wide, and the list uses one column below that. Use columns-sm, columns-md and columns-lg to set the number of columns at 30rem, 40rem and 56rem; a width without a value uses the value of the next smaller width.

Set column-span on a field to span several columns, or column-span-full to span all of them. column-span-sm, column-span-md and column-span-lg set the span at each width in the same way, and a span is limited to the number of columns at each width.

<sa-details columns="3" columns-sm="2" columns-lg="4">
    <sa-display-field asp-for="Reference" />
    <sa-display-field asp-for="LeadTraveller" />
    <sa-display-field asp-for="Email" column-span="2" />
    <sa-display-field asp-for="Departure" />
    <sa-display-field asp-for="Return" />
    <sa-display-field asp-for="Cabin" />
    <sa-display-field asp-for="Party" />
    <sa-display-field asp-for="Notes" column-span-full="true" column-span-lg="3" />
    <sa-display-field asp-for="Total" />
</sa-details>

Horizontal

Set orientation to FieldOrientation.Horizontal to place each label beside its value. Set it on <sa-details> for every field, or on a single <sa-display-field>.

<sa-details orientation="FieldOrientation.Horizontal">
    <sa-display-field asp-for="Reference" />
    <sa-display-field asp-for="Status" />
    <sa-display-field asp-for="LeadTraveller" />
    <sa-display-field asp-for="Email" />
    <sa-display-field asp-for="Departure" />
    <sa-display-field asp-for="Total" />
</sa-details>

Divided

Set variant to DetailsVariant.Divided to separate the fields with rules. It suits a short horizontal list, such as audit information.

<sa-details variant="DetailsVariant.Divided" orientation="FieldOrientation.Horizontal">
    <sa-display-field asp-for="CreatedAt" secondary="by @Model.CreatedBy" />
    <sa-display-field asp-for="UpdatedAt" secondary="by @Model.UpdatedBy" />
    <sa-display-field asp-for="Version" />
    <sa-display-field asp-for="ArchivedAt" />
</sa-details>

Responsive

Set orientation to FieldOrientation.Responsive to stack each label above its value in a narrow list, and place it beside the value once the list is at least 32rem wide.

<sa-details orientation="FieldOrientation.Responsive">
    <sa-display-field asp-for="LeadTraveller" />
    <sa-display-field asp-for="Destination" />
    <sa-display-field asp-for="Departure" />
    <sa-display-field asp-for="Party" />
</sa-details>

Empty values

A null value, a blank string or an empty collection shows a dash in a muted color. Set empty-text to show different text, or set NullDisplayText in the property's [DisplayFormat] attribute to use the same text wherever the property is displayed. Zero and false are values, not empty ones.

<sa-details columns="2">
    @* A dash by default *@
    <sa-display-field asp-for="PromoCode" />
    @* [DisplayFormat(NullDisplayText = "None")] *@
    <sa-display-field asp-for="DietaryNeeds" />
    <sa-display-field asp-for="ArchivedAt" empty-text="Not archived" />
    @* Zero and false are values *@
    <sa-display-field asp-for="Infants" />
</sa-details>

Value types

Values are formatted from the property's metadata:

  • The format attribute, or else the DataFormatString of the property's [DisplayFormat] attribute, formats numbers and dates.
  • An enum value shows its member's [Display] name.
  • A bool shows a check or a cross icon, with "Yes" or "No" for screen readers.
  • An [EmailAddress] property links to a mailto: URL, and a [Url] property links to its URL when it is an http or https URL.
  • href links the value to any URL.
  • A collection shows its items separated by commas.
  • A [DataType(DataType.MultilineText)] property keeps its line breaks.
<sa-details columns="3">
    <sa-display-field asp-for="LeadTraveller" label="Text" />
    <sa-display-field asp-for="Total" label="Number" />
    <sa-display-field asp-for="Departure" label="Date" />
    <sa-display-field asp-for="CreatedAt" label="Date and time" />
    <sa-display-field asp-for="Cabin" label="Enum" />
    <sa-display-field asp-for="Email" label="Email address" />
    <sa-display-field asp-for="ItineraryPage" label="URL" />
    <sa-display-field asp-for="Destination" label="Link" href="#destination-@Model.DestinationId" />
    <sa-display-field asp-for="TravelInsurance" label="Boolean (true)" />
    <sa-display-field asp-for="VisaRequired" label="Boolean (false)" />
    <sa-display-field asp-for="Interests" label="List" />
    <sa-display-field asp-for="Infants" label="Zero" />
    <sa-display-field asp-for="Notes" label="Multiline text" column-span-full="true" />
</sa-details>

Templates and custom content

To render a value with your own markup, such as a badge for a status, set template to the name of a display template, or add a [UIHint] attribute to the property. The template is found like a partial view named DisplayTemplates/{name}, and its model is the value. Templates are only ever used by name: the built-in display templates for a type, such as the checkbox MVC renders for a bool, never apply. A template that cannot be found throws an exception.

Child content replaces the value entirely, and a field with a label and child content needs no asp-for. Set secondary to add muted text after the value.

<sa-details columns="3">
    @* [UIHint("BookingStatus")] renders DisplayTemplates/BookingStatus *@
    <sa-display-field asp-for="Status" />
    @* A named template *@
    <sa-display-field asp-for="Reference" template="Reference" />
    @* Muted text after the value *@
    <sa-display-field asp-for="UpdatedAt" secondary="by @Model.UpdatedBy" />
    @* Child content replaces the value *@
    <sa-display-field asp-for="Interests">
        @foreach (var interest in Model.Interests)
        {
            <sa-badge variant="BadgeVariant.Secondary">@interest</sa-badge>
        }
    </sa-display-field>
    <sa-display-field asp-for="TravelInsurance">
        @(Model.TravelInsurance ? "Included" : "Not included")
    </sa-display-field>
    <sa-display-field label="Duration">7 nights</sa-display-field>
</sa-details>

The status template in this example is a DisplayTemplates/BookingStatus.cshtml view:

@model BookingStatus
@{
    var variant = Model switch
    {
        BookingStatus.Cancelled => BadgeVariant.Destructive,
        BookingStatus.Pending => BadgeVariant.Secondary,
        _ => BadgeVariant.Default,
    };
}
<sa-badge variant="@variant">@Model.ToString()</sa-badge>

Among form inputs

Place a <sa-display-field> among the inputs of a form to show a value that cannot be edited. Outside <sa-details> it takes the label style of an input and the height of a control, so a row of inputs and display fields lines up. A <sa-details> in its own Form Section shows information about the record, such as its audit history, below the inputs.

<form>
    <sa-form-section title="Booking" description="Who is travelling and where.">
        <sa-field-group>
            <sa-form-row>
                <sa-display-field asp-for="Reference" />
                <sa-input asp-for="LeadTraveller" />
            </sa-form-row>
            <sa-form-row>
                <sa-input asp-for="Email" />
                <sa-display-field asp-for="Status" />
            </sa-form-row>
            <sa-textarea asp-for="Notes" rows="3" />
        </sa-field-group>
    </sa-form-section>
    <sa-form-section title="Audit" description="Maintained automatically.">
        <sa-details columns="2">
            <sa-display-field asp-for="CreatedAt" secondary="by @Model.CreatedBy" />
            <sa-display-field asp-for="UpdatedAt" secondary="by @Model.UpdatedBy" />
            <sa-display-field asp-for="Version" />
            <sa-display-field asp-for="ArchivedAt" />
        </sa-details>
    </sa-form-section>
</form>

Record page

Combine details with Page Header and Form Section to build a page that displays a record.

<sa-page-header class="mb-8">
    <sa-page-header-title>@Model.Reference</sa-page-header-title>
    <sa-page-header-description>@Model.Destination · @Model.Departure.ToString("d MMM") – @Model.Return.ToString("d MMM yyyy")</sa-page-header-description>
    <sa-page-header-actions>
        <sa-button variant="ButtonVariant.Outline">Cancel booking</sa-button>
        <sa-button>Edit</sa-button>
    </sa-page-header-actions>
</sa-page-header>

<sa-form-section title="Booking" description="Who is travelling and where.">
    <sa-details columns="2">
        <sa-display-field asp-for="Reference" />
        <sa-display-field asp-for="Status" />
        <sa-display-field asp-for="LeadTraveller" />
        <sa-display-field asp-for="Email" />
        <sa-display-field asp-for="Destination" href="#destination-@Model.DestinationId" />
        <sa-display-field asp-for="Departure" />
        <sa-display-field asp-for="Party" />
        <sa-display-field asp-for="Total" />
        <sa-display-field asp-for="PromoCode" />
    </sa-details>
</sa-form-section>
<sa-form-section title="Notes">
    <sa-details>
        <sa-display-field asp-for="Notes" />
    </sa-details>
</sa-form-section>
<sa-form-section title="Audit" description="Maintained automatically.">
    <sa-details variant="DetailsVariant.Divided" orientation="FieldOrientation.Horizontal">
        <sa-display-field asp-for="CreatedAt" secondary="by @Model.CreatedBy" />
        <sa-display-field asp-for="UpdatedAt" secondary="by @Model.UpdatedBy" />
        <sa-display-field asp-for="Version" />
        <sa-display-field asp-for="ArchivedAt" />
    </sa-details>
</sa-form-section>

Row details

Use details in the expanded rows of a Table, where the labels are shown at a smaller size.

<sa-table-row-details>
    <sa-table>
        <sa-table-header>
            <sa-table-row>
                <sa-table-head class="w-px">
                    <sa-table-row-detail-toggle all="true"/>
                </sa-table-head>
                <sa-table-head>Booking #</sa-table-head>
                <sa-table-head>Destination</sa-table-head>
                <sa-table-head class="text-right">Amount</sa-table-head>
            </sa-table-row>
        </sa-table-header>
        <sa-table-body>
            @foreach (var booking in StaticData.Bookings.Take(3))
            {
                var details = StaticData.DetailsFor(booking.Id);
                <sa-table-row>
                    <sa-table-cell class="w-px">
                        <sa-table-row-detail-toggle aria-label="Show details for @booking.Id"/>
                    </sa-table-cell>
                    <sa-table-cell class="font-medium">@booking.Id</sa-table-cell>
                    <sa-table-cell>@booking.Destination</sa-table-cell>
                    <sa-table-cell class="text-right">@booking.Amount.ToString("N2")</sa-table-cell>
                </sa-table-row>
                <sa-table-row-detail expanded="@(booking.Id == "TRP-4822")">
                    <sa-details columns="4">
                        <sa-display-field asp-for="@booking.Status" />
                        <sa-display-field asp-for="@details.Traveller" label="Lead traveller" />
                        <sa-display-field asp-for="@details.Email" href="mailto:@details.Email" />
                        <sa-display-field asp-for="@details.Party" />
                        <sa-display-field asp-for="@details.Notes" column-span-full="true" />
                    </sa-details>
                </sa-table-row-detail>
            }
        </sa-table-body>
    </sa-table>
</sa-table-row-details>

API Reference

<sa-details>

Renders a <div> element around a <dl> element, forwarding any global attributes to the <div>.

Prop

Type

<sa-display-field>

Renders a <div> element holding the label and the value, forwarding any global attributes. Inside <sa-details> the label is a <dt> and the value a <dd>; elsewhere both are <div> elements. Either label or asp-for is required.

Prop

Type

On this page