Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 84 additions & 18 deletions aspnetcore/blazor/forms/input-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The components in the table are also supported outside of a form in Razor compon
| <xref:Microsoft.AspNetCore.Components.Forms.InputSelect%601> | `<select>` |
| <xref:Microsoft.AspNetCore.Components.Forms.InputText> | `<input>` |
| <xref:Microsoft.AspNetCore.Components.Forms.InputTextArea> | `<textarea>` |
| [`Label<TValue>`](#label-component) (.NET 11 or later) | `<label>` |

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

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

> The Production Date field must be a date.

<!-- UPDATE 11.0 The feature has been backlogged.
https://github.com/dotnet/aspnetcore/issues/49147
:::moniker-end

> [!NOTE]
> Alternatively, the [`[Display]` attribute](xref:System.ComponentModel.DataAnnotations.DisplayAttribute) on the model class property is supported:
>
> ```csharp
> [Required, Display(Name = "Production Date")]
> public DateTime ProductionDate { get; set; }
> ```
>
> [`[DisplayName]` attribute](xref:System.ComponentModel.DisplayNameAttribute) is also supported:
>
> ```csharp
> [Required, DisplayName("Production Date")]
> public DateTime ProductionDate { get; set; }
> ```
>
> 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.
:::moniker range=">= aspnetcore-11.0"

<!-- UPDATE 11.0 - API cross-link

<xref:Microsoft.AspNetCore.Components.Forms.DisplayName%601>
-->
The `DisplayName` component can be used to display property names from metadata attributes

```csharp
[Required, DisplayName("Production Date")]
public DateTime ProductionDate { get; set; }
```

The [`[Display]` attribute](xref:System.ComponentModel.DataAnnotations.DisplayAttribute) on the model class property is supported:

```csharp
[Required, Display(Name = "Production Date")]
public DateTime ProductionDate { get; set; }
```

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.

Use the `DisplayName` component in labels or table headers:

```razor
<label>
<DisplayName For="@(() => Model!.ProductionDate)" />
<InputDate @bind-Value="Model!.ProductionDate" />
</label>
```

:::moniker-end

:::moniker range=">= aspnetcore-11.0"

## `Label` component

<!-- UPDATE 11.0 - API cross-link

<xref:Microsoft.AspNetCore.Components.Forms.Label%601>
-->

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.

### Nested pattern

The nested pattern wraps the input component inside the label:

```razor
<Label For="() => Model!.ProductionDate">
<InputDate @bind-Value="Model!.ProductionDate" />
</Label>
```

This renders:

```html
<label>Production Date<input type="date" ... /></label>
```

### Non-nested pattern

For accessibility requirements or styling flexibility, use the non-nested pattern where the label's `for` attribute references the input's `id`:

```razor
<Label For="() => Model!.ProductionDate" />
<InputDate @bind-Value="Model!.ProductionDate" />
```

This renders:

```html
<label for="Model_ProductionDate">Production Date</label>
<input id="Model_ProductionDate" type="date" ... />
```

The `id` attribute is automatically sanitized to create a valid HTML id (dots are replaced with underscores to avoid CSS selector conflicts).

Input components automatically generate an `id` attribute based on the bound expression. If an explicit `id` is provided, it takes precedence:

```razor
<Label For="() => Model!.ProductionDate" for="prod-date" />
<InputDate @bind-Value="Model!.ProductionDate" id="prod-date" />
```

:::moniker-end

## Error message template support
Expand Down
16 changes: 14 additions & 2 deletions aspnetcore/blazor/fundamentals/environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ For general guidance on ASP.NET Core app configuration, see <xref:fundamentals/e

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

:::moniker range=">= aspnetcore-8.0"
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"

Blazor Web App:

:::moniker-end

:::moniker range=">= aspnetcore-8.0"

```html
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
Expand All @@ -148,10 +152,16 @@ Blazor Web App:
> [!NOTE]
> 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>.

:::moniker-end

:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"

Standalone Blazor WebAssembly:

:::moniker-end

:::moniker range="< aspnetcore-11.0"

```html
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
Expand All @@ -167,6 +177,8 @@ Standalone Blazor WebAssembly:

**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>.

:::moniker-end

:::moniker range="< aspnetcore-10.0"

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

:::moniker-end

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();`):
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();`):

```csharp
Console.WriteLine(
Expand Down
30 changes: 28 additions & 2 deletions aspnetcore/blazor/fundamentals/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -577,10 +577,14 @@ For the `configureLogging` log level value, pass the argument as either the stri

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

:::moniker range=">= aspnetcore-8.0"
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"

Blazor Web App:

:::moniker-end

:::moniker range=">= aspnetcore-8.0"

```html
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
Expand All @@ -594,10 +598,16 @@ Blazor Web App:
</script>
```

:::moniker-end

:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"

Blazor Server:

:::moniker-end

:::moniker range="< aspnetcore-11.0"

```html
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
Expand All @@ -609,14 +619,20 @@ Blazor Server:
</script>
```

:::moniker-end

**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>.

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

:::moniker range=">= aspnetcore-8.0"
:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"

Blazor Web App:

:::moniker-end

:::moniker range=">= aspnetcore-8.0"

```html
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
Expand All @@ -630,10 +646,18 @@ Blazor Web App:
</script>
```

**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>.

:::moniker-end

:::moniker range=">= aspnetcore-8.0 < aspnetcore-11.0"

Blazor Server:

:::moniker-end

:::moniker range="< aspnetcore-11.0"

```html
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
Expand All @@ -647,6 +671,8 @@ Blazor Server:

**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>.

:::moniker-end

> [!NOTE]
> 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).

Expand Down
94 changes: 72 additions & 22 deletions aspnetcore/blazor/fundamentals/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ There are two <xref:Microsoft.AspNetCore.Components.Routing.NavLinkMatch> option

:::moniker-end

:::moniker range=">= aspnetcore-11.0"

<!-- UPDATE 11.0 - API cross-link

<xref:Microsoft.AspNetCore.Components.Routing.NavLink.RelativeToCurrentUri?displayProperty=nameWithType>

-->

Set `NavLink.RelativeToCurrentUri` to `true` to resolve the `href` relative to the current page path instead of the app's base URI:

```razor
<NavLink href="details" RelativeToCurrentUri="true">View Details</NavLink>
```

If the current URI is `/docs/getting-started/installation`, the preceding link navigates to `/docs/getting-started/details`.

:::moniker-end

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:

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

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

:::moniker-end

:::moniker range=">= aspnetcore-11.0"

<!-- UPDATE 11.0 - API cross-link

<xref:Microsoft.AspNetCore.Components.NavigationOptions.RelativeToCurrentUri>

-->

* <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`.
* <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`.
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.HistoryEntryState>: Gets or sets the state to append to the history entry.
* `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`.

In the following example:

* The state appended to the history entry is "`Navigation state`."
* If the current URI is `/docs/getting-started/installation`, navigation results in a request for `/docs/getting-started/configuration`.

```csharp
Navigation.NavigateTo("/configuration", new NavigationOptions
{
HistoryEntryState = "Navigation state",
RelativeToCurrentUri = true
});
```

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.

:::moniker-end

:::moniker range=">= aspnetcore-7.0 < aspnetcore-11.0"

* <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`.
* <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`.
* <xref:Microsoft.AspNetCore.Components.NavigationOptions.HistoryEntryState>: Gets or sets the state to append to the history entry.

In the following example, the state appended to the history entry is "`Navigation state`."

```csharp
Navigation.NavigateTo("/path", new NavigationOptions
Expand Down Expand Up @@ -1354,28 +1408,24 @@ For the following demonstration, a consistent, standard naming convention is use
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:

```diff
<div class="nav-scrollable"
onclick="document.querySelector('.navbar-toggler').click()">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu"
aria-hidden="true"></span> Home
</NavLink>
</div>

+ @foreach (var name in GetRoutableComponents())
+ {
+ <div class="nav-item px-3">
+ <NavLink class="nav-link"
+ href="@Regex.Replace(name, @"(\B[A-Z]|\d+)", "-$1").ToLower()">
+ @Regex.Replace(name, @"(\B[A-Z]|\d+)", " $1")
+ </NavLink>
+ </div>
+ }

</nav>
</div>
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu"
aria-hidden="true"></span> Home
</NavLink>
</div>

+ @foreach (var name in GetRoutableComponents())
+ {
+ <div class="nav-item px-3">
+ <NavLink class="nav-link"
+ href="@Regex.Replace(name, @"(\B[A-Z]|\d+)", "-$1").ToLower()">
+ @Regex.Replace(name, @"(\B[A-Z]|\d+)", " $1")
+ </NavLink>
+ </div>
+ }
</nav>
```

The `GetRoutableComponents` method in the `@code` block:
Expand Down
Loading
Loading