Details

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

<sa-details columns-md="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-md="...">
    <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-md to lay the fields out in a grid once the list is at least 40rem wide; narrower lists use one column. 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. Use columns, columns-sm, columns-md and columns-lg to set the number of columns at the smallest width, 30rem, 40rem and 56rem; a width without a value uses the value of the next smaller width. The columns work as they do in a Grid.

Set column-span on a field to a number of columns, or to 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-md="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" column-span-lg="3" />
    <sa-display-field asp-for="Total" />
</sa-details>

Column start

Set column-start to the column a field starts at, from 1 to 12, to begin a new row or leave a gap. In this example the dates start a new row and the total sits under the cabin in the last column. column-start-sm, column-start-md and column-start-lg set the start at each width, and auto places the field after the one before it again. The start is ignored where the list has one column or the field would extend past the last column. Starts work as they do in a Grid.

<sa-details columns-md="3">
    <sa-display-field asp-for="Reference" />
    <sa-display-field asp-for="LeadTraveller" />
    <sa-display-field asp-for="Departure" column-start="1" />
    <sa-display-field asp-for="Return" />
    <sa-display-field asp-for="Cabin" />
    <sa-display-field asp-for="Total" column-start="3" />
</sa-details>

Horizontal

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

<sa-details orientation="DetailsOrientation.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="DetailsOrientation.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>

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. A field with a template skips it for an empty value, unless template-renders-empty is set, which passes empty values to the template too.

<sa-details columns-md="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-md="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" />
</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-md="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, for example in a Grid, 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-grid columns-md="2">
            <sa-display-field asp-for="Reference" />
            <sa-input asp-for="LeadTraveller" />
            <sa-input asp-for="Email" />
            <sa-display-field asp-for="Status" />
            <sa-textarea asp-for="Notes" rows="3" column-span="full" />
        </sa-grid>
    </sa-form-section>
    <sa-form-section title="Audit" description="Maintained automatically.">
        <sa-details columns-md="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-md="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="DetailsOrientation.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="true">
    <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-md="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" />
                </sa-details>
            </sa-table-row-detail>
        }
    </sa-table-body>
</sa-table>

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