Skip to content

Commit ce68a2c

Browse files
authored
Merge pull request #36755 from dotnet/main
Merge to Live
2 parents 318fb85 + d55c12c commit ce68a2c

File tree

25 files changed

+1762
-85
lines changed

25 files changed

+1762
-85
lines changed

aspnetcore/blazor/forms/input-components.md

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ The components in the table are also supported outside of a form in Razor compon
3737
| <xref:Microsoft.AspNetCore.Components.Forms.InputSelect%601> | `<select>` |
3838
| <xref:Microsoft.AspNetCore.Components.Forms.InputText> | `<input>` |
3939
| <xref:Microsoft.AspNetCore.Components.Forms.InputTextArea> | `<textarea>` |
40+
| [`Label<TValue>`](#label-component) (.NET 11 or later) | `<label>` |
4041

4142
For more information on the <xref:Microsoft.AspNetCore.Components.Forms.InputFile> component, see <xref:blazor/file-uploads>.
4243

@@ -458,28 +459,93 @@ The validation summary displays the friendly name when the field's value is inva
458459

459460
> The Production Date field must be a date.
460461
461-
<!-- UPDATE 11.0 The feature has been backlogged.
462-
https://github.com/dotnet/aspnetcore/issues/49147
462+
:::moniker-end
463463

464-
> [!NOTE]
465-
> Alternatively, the [`[Display]` attribute](xref:System.ComponentModel.DataAnnotations.DisplayAttribute) on the model class property is supported:
466-
>
467-
> ```csharp
468-
> [Required, Display(Name = "Production Date")]
469-
> public DateTime ProductionDate { get; set; }
470-
> ```
471-
>
472-
> [`[DisplayName]` attribute](xref:System.ComponentModel.DisplayNameAttribute) is also supported:
473-
>
474-
> ```csharp
475-
> [Required, DisplayName("Production Date")]
476-
> public DateTime ProductionDate { get; set; }
477-
> ```
478-
>
479-
> Between the two approaches, the `[Display]` attribute is recommended, which makes additional properties available. The `[Display]` attribute also enables assigning a resource type for localization.
464+
:::moniker range=">= aspnetcore-11.0"
465+
466+
<!-- UPDATE 11.0 - API cross-link
467+
468+
<xref:Microsoft.AspNetCore.Components.Forms.DisplayName%601>
469+
-->
470+
The `DisplayName` component can be used to display property names from metadata attributes
471+
472+
```csharp
473+
[Required, DisplayName("Production Date")]
474+
public DateTime ProductionDate { get; set; }
475+
```
476+
477+
The [`[Display]` attribute](xref:System.ComponentModel.DataAnnotations.DisplayAttribute) on the model class property is supported:
478+
479+
```csharp
480+
[Required, Display(Name = "Production Date")]
481+
public DateTime ProductionDate { get; set; }
482+
```
483+
484+
Between the two approaches, the `[Display]` attribute is recommended, which makes additional properties available. The `[Display]` attribute also enables assigning a resource type for localization. When both attributes are present, `[Display]` takes precedence over `[DisplayName]`. If neither attribute is present, the component falls back to the property name.
485+
486+
Use the `DisplayName` component in labels or table headers:
487+
488+
```razor
489+
<label>
490+
<DisplayName For="@(() => Model!.ProductionDate)" />
491+
<InputDate @bind-Value="Model!.ProductionDate" />
492+
</label>
493+
```
494+
495+
:::moniker-end
496+
497+
:::moniker range=">= aspnetcore-11.0"
498+
499+
## `Label` component
500+
501+
<!-- UPDATE 11.0 - API cross-link
480502
503+
<xref:Microsoft.AspNetCore.Components.Forms.Label%601>
481504
-->
482505

506+
The `Label` component renders a `<label>` element that automatically extracts the display name from a model property using `[Display]` or `[DisplayName]` attributes. This simplifies form creation by eliminating the need to manually specify label text.
507+
508+
### Nested pattern
509+
510+
The nested pattern wraps the input component inside the label:
511+
512+
```razor
513+
<Label For="() => Model!.ProductionDate">
514+
<InputDate @bind-Value="Model!.ProductionDate" />
515+
</Label>
516+
```
517+
518+
This renders:
519+
520+
```html
521+
<label>Production Date<input type="date" ... /></label>
522+
```
523+
524+
### Non-nested pattern
525+
526+
For accessibility requirements or styling flexibility, use the non-nested pattern where the label's `for` attribute references the input's `id`:
527+
528+
```razor
529+
<Label For="() => Model!.ProductionDate" />
530+
<InputDate @bind-Value="Model!.ProductionDate" />
531+
```
532+
533+
This renders:
534+
535+
```html
536+
<label for="Model_ProductionDate">Production Date</label>
537+
<input id="Model_ProductionDate" type="date" ... />
538+
```
539+
540+
The `id` attribute is automatically sanitized to create a valid HTML id (dots are replaced with underscores to avoid CSS selector conflicts).
541+
542+
Input components automatically generate an `id` attribute based on the bound expression. If an explicit `id` is provided, it takes precedence:
543+
544+
```razor
545+
<Label For="() => Model!.ProductionDate" for="prod-date" />
546+
<InputDate @bind-Value="Model!.ProductionDate" id="prod-date" />
547+
```
548+
483549
:::moniker-end
484550

485551
## Error message template support

aspnetcore/blazor/fundamentals/environments.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,14 @@ For general guidance on ASP.NET Core app configuration, see <xref:fundamentals/e
124124

125125
The following example starts Blazor in the `Staging` environment if the hostname includes `localhost`. Otherwise, the environment is set to its default value.
126126

127-
:::moniker range=">= aspnetcore-8.0"
127+
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"
128128

129129
Blazor Web App:
130130

131+
:::moniker-end
132+
133+
:::moniker range=">= aspnetcore-8.0"
134+
131135
```html
132136
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
133137
<script>
@@ -148,10 +152,16 @@ Blazor Web App:
148152
> [!NOTE]
149153
> For Blazor Web Apps that set the `webAssembly` > `environment` property in `Blazor.start` configuration, it's wise to match the server-side environment to the environment set on the `environment` property. Otherwise, prerendering on the server operates under a different environment than rendering on the client, which results in arbitrary effects. For general guidance on setting the environment for a Blazor Web App, see <xref:fundamentals/environments>.
150154
155+
:::moniker-end
156+
157+
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"
158+
151159
Standalone Blazor WebAssembly:
152160

153161
:::moniker-end
154162

163+
:::moniker range="< aspnetcore-11.0"
164+
155165
```html
156166
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
157167
<script>
@@ -167,6 +177,8 @@ Standalone Blazor WebAssembly:
167177

168178
**In the preceding example, the `{BLAZOR SCRIPT}` placeholder is the Blazor script path and file name.** For the location of the script, see <xref:blazor/project-structure#location-of-the-blazor-script>.
169179

180+
:::moniker-end
181+
170182
:::moniker range="< aspnetcore-10.0"
171183

172184
Using the `environment` property overrides the environment set by the [`Blazor-Environment` header](#set-the-client-side-environment-via-header).
@@ -175,7 +187,7 @@ The preceding approach sets the client's environment without changing the `Blazo
175187

176188
:::moniker-end
177189

178-
To log the environment to the console in either a standalone Blazor WebAssembly app or the `.Client` project of a Blazor Web App, place the following C# code in the `Program` file after the <xref:Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHost> is created with <xref:Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostBuilder.CreateDefault%2A?displayProperty=nameWithType> and before the line that builds and runs the project (`await builder.Build().RunAsync();`):
190+
To log the environment to the console in either a standalone Blazor WebAssembly app (all release versions) or the `.Client` project of a Blazor Web App (.NET 8 or later), place the following C# code in the `Program` file after the <xref:Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHost> is created with <xref:Microsoft.AspNetCore.Components.WebAssembly.Hosting.WebAssemblyHostBuilder.CreateDefault%2A?displayProperty=nameWithType> and before the line that builds and runs the project (`await builder.Build().RunAsync();`):
179191

180192
```csharp
181193
Console.WriteLine(

aspnetcore/blazor/fundamentals/logging.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,10 +577,14 @@ For the `configureLogging` log level value, pass the argument as either the stri
577577

578578
Example 1: Set the <xref:Microsoft.Extensions.Logging.LogLevel.Information> log level with a string value.
579579

580-
:::moniker range=">= aspnetcore-8.0"
580+
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"
581581

582582
Blazor Web App:
583583

584+
:::moniker-end
585+
586+
:::moniker range=">= aspnetcore-8.0"
587+
584588
```html
585589
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
586590
<script>
@@ -594,10 +598,16 @@ Blazor Web App:
594598
</script>
595599
```
596600

601+
:::moniker-end
602+
603+
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"
604+
597605
Blazor Server:
598606

599607
:::moniker-end
600608

609+
:::moniker range="< aspnetcore-11.0"
610+
601611
```html
602612
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
603613
<script>
@@ -609,14 +619,20 @@ Blazor Server:
609619
</script>
610620
```
611621

622+
:::moniker-end
623+
612624
**In the preceding example, the `{BLAZOR SCRIPT}` placeholder is the Blazor script path and file name.** For the location of the script, see <xref:blazor/project-structure#location-of-the-blazor-script>.
613625

614626
Example 2: Set the <xref:Microsoft.Extensions.Logging.LogLevel.Information> log level with an integer value.
615627

616-
:::moniker range=">= aspnetcore-8.0"
628+
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"
617629

618630
Blazor Web App:
619631

632+
:::moniker-end
633+
634+
:::moniker range=">= aspnetcore-8.0"
635+
620636
```html
621637
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
622638
<script>
@@ -630,10 +646,18 @@ Blazor Web App:
630646
</script>
631647
```
632648

649+
**In the preceding example, the `{BLAZOR SCRIPT}` placeholder is the Blazor script path and file name.** For the location of the script, see <xref:blazor/project-structure#location-of-the-blazor-script>.
650+
651+
:::moniker-end
652+
653+
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"
654+
633655
Blazor Server:
634656

635657
:::moniker-end
636658

659+
:::moniker range="< aspnetcore-11.0"
660+
637661
```html
638662
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
639663
<script>
@@ -647,6 +671,8 @@ Blazor Server:
647671

648672
**In the preceding example, the `{BLAZOR SCRIPT}` placeholder is the Blazor script path and file name.** For the location of the script, see <xref:blazor/project-structure#location-of-the-blazor-script>.
649673

674+
:::moniker-end
675+
650676
> [!NOTE]
651677
> Using an integer to specify the logging level in Example 2, often referred to as a *magic number* or *magic constant*, is considered a poor coding practice because the integer doesn't clearly identify the logging level when viewing the source code. If minimizing the bytes transferred to the browser is a priority, using an integer might be justified (consider removing the comment in such cases).
652678

aspnetcore/blazor/fundamentals/navigation.md

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,24 @@ There are two <xref:Microsoft.AspNetCore.Components.Routing.NavLinkMatch> option
7878

7979
:::moniker-end
8080

81+
:::moniker range=">= aspnetcore-11.0"
82+
83+
<!-- UPDATE 11.0 - API cross-link
84+
85+
<xref:Microsoft.AspNetCore.Components.Routing.NavLink.RelativeToCurrentUri?displayProperty=nameWithType>
86+
87+
-->
88+
89+
Set `NavLink.RelativeToCurrentUri` to `true` to resolve the `href` relative to the current page path instead of the app's base URI:
90+
91+
```razor
92+
<NavLink href="details" RelativeToCurrentUri="true">View Details</NavLink>
93+
```
94+
95+
If the current URI is `/docs/getting-started/installation`, the preceding link navigates to `/docs/getting-started/details`.
96+
97+
:::moniker-end
98+
8199
Additional <xref:Microsoft.AspNetCore.Components.Routing.NavLink> component attributes are passed through to the rendered anchor tag. In the following example, the <xref:Microsoft.AspNetCore.Components.Routing.NavLink> component includes the `target` attribute:
82100

83101
```razor
@@ -751,9 +769,45 @@ The <xref:Microsoft.AspNetCore.Components.NavigationManager> uses the browser's
751769

752770
Pass <xref:Microsoft.AspNetCore.Components.NavigationOptions> to <xref:Microsoft.AspNetCore.Components.NavigationManager.NavigateTo%2A> to control the following behaviors:
753771

772+
:::moniker-end
773+
774+
:::moniker range=">= aspnetcore-11.0"
775+
776+
<!-- UPDATE 11.0 - API cross-link
777+
778+
<xref:Microsoft.AspNetCore.Components.NavigationOptions.RelativeToCurrentUri>
779+
780+
-->
781+
754782
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.ForceLoad>: Bypass client-side routing and force the browser to load the new page from the server, whether or not the URI is handled by the client-side router. The default value is `false`.
755783
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.ReplaceHistoryEntry>: Replace the current entry in the history stack. If `false`, append the new entry to the history stack. The default value is `false`.
756784
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.HistoryEntryState>: Gets or sets the state to append to the history entry.
785+
* `RelativeToCurrentUri`: When `true`, the URI is resolved relative to the current page path instead of the app's base URI. The default value is `false`.
786+
787+
In the following example:
788+
789+
* The state appended to the history entry is "`Navigation state`."
790+
* If the current URI is `/docs/getting-started/installation`, navigation results in a request for `/docs/getting-started/configuration`.
791+
792+
```csharp
793+
Navigation.NavigateTo("/configuration", new NavigationOptions
794+
{
795+
HistoryEntryState = "Navigation state",
796+
RelativeToCurrentUri = true
797+
});
798+
```
799+
800+
For more information on obtaining the state associated with the target history entry while handling location changes, see the [Handle/prevent location changes](#handleprevent-location-changes) section.
801+
802+
:::moniker-end
803+
804+
:::moniker range=">= aspnetcore-7.0 < aspnetcore-11.0"
805+
806+
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.ForceLoad>: Bypass client-side routing and force the browser to load the new page from the server, whether or not the URI is handled by the client-side router. The default value is `false`.
807+
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.ReplaceHistoryEntry>: Replace the current entry in the history stack. If `false`, append the new entry to the history stack. The default value is `false`.
808+
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.HistoryEntryState>: Gets or sets the state to append to the history entry.
809+
810+
In the following example, the state appended to the history entry is "`Navigation state`."
757811

758812
```csharp
759813
Navigation.NavigateTo("/path", new NavigationOptions
@@ -1354,28 +1408,24 @@ For the following demonstration, a consistent, standard naming convention is use
13541408
In the Razor markup of the `NavMenu` component (`NavMenu.razor`) under the default `Home` page, <xref:Microsoft.AspNetCore.Components.Routing.NavLink> components are added from a collection:
13551409

13561410
```diff
1357-
<div class="nav-scrollable"
1358-
onclick="document.querySelector('.navbar-toggler').click()">
1359-
<nav class="flex-column">
1360-
<div class="nav-item px-3">
1361-
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
1362-
<span class="bi bi-house-door-fill-nav-menu"
1363-
aria-hidden="true"></span> Home
1364-
</NavLink>
1365-
</div>
1366-
1367-
+ @foreach (var name in GetRoutableComponents())
1368-
+ {
1369-
+ <div class="nav-item px-3">
1370-
+ <NavLink class="nav-link"
1371-
+ href="@Regex.Replace(name, @"(\B[A-Z]|\d+)", "-$1").ToLower()">
1372-
+ @Regex.Replace(name, @"(\B[A-Z]|\d+)", " $1")
1373-
+ </NavLink>
1374-
+ </div>
1375-
+ }
1376-
1377-
</nav>
1378-
</div>
1411+
<nav class="flex-column">
1412+
<div class="nav-item px-3">
1413+
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
1414+
<span class="bi bi-house-door-fill-nav-menu"
1415+
aria-hidden="true"></span> Home
1416+
</NavLink>
1417+
</div>
1418+
1419+
+ @foreach (var name in GetRoutableComponents())
1420+
+ {
1421+
+ <div class="nav-item px-3">
1422+
+ <NavLink class="nav-link"
1423+
+ href="@Regex.Replace(name, @"(\B[A-Z]|\d+)", "-$1").ToLower()">
1424+
+ @Regex.Replace(name, @"(\B[A-Z]|\d+)", " $1")
1425+
+ </NavLink>
1426+
+ </div>
1427+
+ }
1428+
</nav>
13791429
```
13801430

13811431
The `GetRoutableComponents` method in the `@code` block:

0 commit comments

Comments
 (0)