Skip to content

Conversation

@ilonatommy
Copy link
Member

@ilonatommy ilonatommy commented Dec 3, 2025

Summary

This PR adds the DisplayName<TValue> component to enable displaying property display names from [Display] and [DisplayName] attributes in Blazor applications, addressing the feature gap identified in issue #49147.

Background

Blazor currently lacks a built-in mechanism to display property names from metadata attributes like MVC's @Html.DisplayNameFor() helper. This forces developers to either:

  • Hardcode label text (violating DRY principles and making localization difficult)
  • Build custom reflection-based solutions
  • Duplicate display name information across models and views

The new DisplayName<TValue> component provides an attribute-based solution that follows the same familiar pattern as other Blazor form components like ValidationMessage<TValue>.

Fixes #49147

Changes

Public API

namespace Microsoft.AspNetCore.Components.Forms;

public class DisplayName<TValue> : ComponentBase
{
    [Parameter]
    [EditorRequired]
    public Expression<Func<TValue>>? For { get; set; }
}

Implementation Details

The component extracts the property name from the expression and reads display metadata:

  1. First checks for DisplayAttribute.Name (System.ComponentModel.DataAnnotations)
  2. Falls back to DisplayNameAttribute.DisplayName (System.ComponentModel)
  3. Uses the property name itself if no attributes are present

Tests

Unit tests in src/Components/Web/test/Forms/DisplayNameTest.cs:

  • ✅ Throws when For parameter is missing
  • ✅ Reads DisplayAttribute.Name correctly
  • ✅ Reads DisplayNameAttribute.DisplayName correctly
  • DisplayAttribute takes precedence over DisplayNameAttribute
  • ✅ Falls back to property name when no attributes present
  • ✅ Works with different property types (string, decimal, DateTime, int)

E2E test in src/Components/test/E2ETest/Tests/FormsTest.cs:

  • DisplayNamelReadsAttributesCorrectly() - Verifies the component renders correctly in a browser with all attribute scenarios

API usage

Basic form usage:

<EditForm Model="@product">
    <div class="mb-3">
        <label class="form-label">
            <DisplayName For="@(() => product.Name)" />
        </label>
        <InputText @bind-Value="product.Name" class="form-control" />
        <ValidationMessage For="@(() => product.Name)" />
    </div>
</EditForm>

Table headers:

<table class="table">
    <thead>
        <tr>
            <th><DisplayName For="@(() => product.Name)" /></th>
            <th><DisplayName For="@(() => product.Price)" /></th>
            <th><DisplayName For="@(() => product.ReleaseDate)" /></th>
        </tr>
    </thead>
</table>

Model example:

public class Product
{
    [Display(Name = "Product Name")]
    public string Name { get; set; }
    
    [DisplayName("Unit Price")]
    public decimal Price { get; set; }
    
    [Display(Name = "Release Date")]
    public DateTime ReleaseDate { get; set; }
}

Copilot AI review requested due to automatic review settings December 3, 2025 15:34
@ilonatommy ilonatommy requested a review from a team as a code owner December 3, 2025 15:34
@ilonatommy ilonatommy added the area-blazor Includes: Blazor, Razor Components label Dec 3, 2025
@ilonatommy ilonatommy added this to the .NET 11 Planning milestone Dec 3, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces the DisplayNameLabel<TValue> component to display property display names from metadata attributes ([Display] and [DisplayName]), providing Blazor with functionality similar to MVC's @Html.DisplayNameFor() helper. The component addresses a feature gap that previously required developers to hardcode labels or build custom reflection-based solutions.

Key Changes:

  • New DisplayNameLabel<TValue> component that extracts and displays property names from metadata attributes
  • Comprehensive unit tests covering attribute precedence, fallback behavior, and various property types
  • E2E test validating browser rendering with real-world scenarios

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/Components/Web/src/Forms/DisplayNameLabel.cs Core component implementation with expression parsing and attribute reading logic
src/Components/Web/test/Forms/DisplayNameLabelTest.cs Unit tests covering attribute precedence, type support, and error handling
src/Components/test/E2ETest/Tests/FormsTest.cs Browser-based integration test verifying component rendering
src/Components/test/testassets/BasicTestApp/FormsTest/DisplayNameLabelComponent.razor Test component demonstrating all attribute scenarios
src/Components/test/testassets/BasicTestApp/Index.razor Navigation entry for the test component
src/Components/Web/src/PublicAPI.Unshipped.txt Public API surface additions

@campersau
Copy link
Contributor

The name DisplayNameLabel might be missleading. I thought it would render a <label> but it only renders the plain name.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to ensure localization works with this component.

@ilonatommy
Copy link
Member Author

We need to ensure localization works with this component.

Added tests + tested multiple localizing resources manually.

@ilonatommy ilonatommy requested a review from javiercn December 11, 2025 09:38
@ilonatommy ilonatommy self-assigned this Dec 11, 2025
@ilonatommy ilonatommy requested a review from oroztocil December 12, 2025 09:29
@ilonatommy ilonatommy requested a review from maraf December 15, 2025 09:24
Comment on lines +30 to +32
<label for="Input.NewPassword" class="form-label">
<DisplayName For="() => Input.NewPassword" />
</label>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should have Label rather than DisplayName or in addition to.

The main use case for this is to essentially create a label, which can happen in two ways

  <label for="input-name">Label text</label>
  <input name="input-name" />

Or

<label>
Label text
<input name="input-name" />
</label>

We don't need to tackle this here, but I would suggest filing a separate issue for it for us to consider. @danroth27 thoughts?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we did wanted to do this, we would also need to take into account Editor and HtmlFieldPrefix to compute the right name.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, having a higher-level Label component in addition to DisplayName makes sense to me.

maraf
maraf previously approved these changes Dec 15, 2025
@maraf maraf dismissed their stale review December 15, 2025 17:03

Sorry. I missed other feedback still open

@ilonatommy
Copy link
Member Author

Sorry. I missed other feedback still open

I think the other feedback is not blocking:

We don't need to tackle this here, but I would suggest filing a separate issue for it for us to consider.

@javiercn, I will do that now and move the discussion to there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DisplayNameFor support in Blazor

5 participants