Chapter 18: Building forms with Tag Helpers
This chapter introduces Tag Helpers as Razor features that generate and enhance server-rendered HTML, especially user-friendly forms that bind and validate data correctly.
After this chapter you will be able to
- Tag Helper purpose. Explain what Tag Helpers are and how they customize or generate HTML in Razor templates using information from C# models.
- Form-model integration. Describe how form Tag Helpers help generate correct form element names and IDs from a C# model so submitted values can be model-bound back into a Razor Pages application.
- Tag Helper purpose. Explain what Tag Helpers are and how their asp-* attributes or custom elements modify the HTML element they are attached to while integrating server-side values into generated HTML.
- Metadata-driven form generation. Describe how form Tag Helpers use a property named by asp-for, its type, and DataAnnotations metadata to generate labels, input values, id and name attributes, suitable input types, and validation errors.
- Model-bound form generation. Explain how form Tag Helpers use properties exposed by a Razor Page's PageModel to generate form markup, including element names, IDs, values, form actions, and validation-related attributes. Describe the checkout page example in which a UserBindingModel is exposed as an Input property and referenced by Tag Helpers.
- Form Tag Helper activation. Describe how adding an asp- attribute to a form activates the FormTagHelper and causes it to generate the form's action URL. Explain that asp-page selects the Razor Page that receives the submitted form.
- Same-page post behavior. Explain that omitting asp-page makes a Razor Pages form post back to the URL that served it, which is commonly handled by the same Razor Page. State that method="post" must then be added manually, because the browser otherwise defaults the form to GET.
- Route values and handlers. Describe how asp-route-* attributes supply route parameter values when the Form Tag Helper generates an action URL, such as asp-route-id for an {id} route parameter. Explain that asp-page-handler selects the Razor Page handler that receives the POST.
- Label Tag Helper generation. Explain how the Label Tag Helper uses the asp-for attribute to generate a label's visible caption and for attribute from a PageModel property. Describe how a [Display] attribute supplies the caption text, while the property name is used when [Display] is absent.
- Label and control association. Describe how the generated for attribute identifies the ID of the form control that a label refers to, and why this association is important for accessibility. Explain that Label Tag Helper output works with IDs generated by other Tag Helpers.
- Input type inference. Explain how the Input Tag Helper uses an asp-for property, its CLR type, and its DataAnnotations attributes to choose the generated HTML input type. Describe the Email property example, where a string with [EmailAddress] produces an email input rather than the default text input.
- Binding and validation markup. Describe how the Input Tag Helper generates id, name, value, and data-val-* attributes from a bound property. Explain that the name retains dotted property notation for model binding, while client-side validation attributes can be used by JavaScript validation libraries for immediate feedback.
- Select Tag Helper bindings. Describe how the Select Tag Helper uses asp-for to bind a select element to a PageModel property and asp-items to supply the available options as an IEnumerable<SelectListItem>. Explain that the model needs a property for the selected value or values and a separate options-list property.
- Single and multiple selections. Explain how a select element supports a drop-down or single-selection list box versus a multiselect list box. State that binding asp-for to an IEnumerable selected-values property causes the Select Tag Helper to add the multiple HTML attribute.
- Property validation messages. Describe how the Validation Message Tag Helper uses a <span> with asp-validation-for to display validation errors for one view-model property. Explain that it works for both client-side validation and server-side ModelState errors, and updates when client-side validation reruns after the user changes the input.
- Validation summary configuration. Explain how the Validation Summary Tag Helper uses a <div> with asp-validation-summary to render a list of ModelState errors for the form. Distinguish the None, ModelOnly, and All ValidationSummary values, especially that model-level errors require a summary to be visible.
- Anchor Tag Helper link generation. Explain how the Anchor Tag Helper generates an <a> element's href for a Razor Page by using routing. Describe using asp-page, and optionally asp-page-handler and asp-route-* attributes, to identify the destination page, handler, and route values.
- Routing-based link maintenance. Justify using the Anchor Tag Helper instead of embedding hardcoded URLs in views. Explain that routing generates the URL from page and route information, reducing duplicated URL strings that would otherwise need updating across views.
- Browser caching trade-off. Explain why browser caching is useful for mostly unchanged static assets but can cause users to keep outdated images, CSS, or JavaScript after a file changes.
- Cache-busting query strings. Describe how changing a query string such as ?v=1 to ?v=2 makes a browser treat the URL as a new resource and request a fresh copy.
- Append Version Tag Helper. Describe how adding the asp-append-version attribute to a script, img, or link element loads the referenced file and appends a query-string hash based on its contents.
- Environment-specific markup. Describe why a Razor view might render different HTML in development, testing, and production environments, such as using readable assets during development or showing a testing banner that is absent in production.
- Environment Tag Helper usage. Explain how the EnvironmentTagHelper conditionally renders its enclosed markup based on the current hosting environment, and distinguish it from placing an equivalent C# if statement directly in a Razor template.
What it builds on
- Creating Razor views (chapter 17) · Razor views and templates that combine HTML with C#.
- Creating dynamic web pages with Razor (chapter 17) · Generating dynamic web-page markup with Razor.
- From request to binding model: Making the request useful (chapter 16) · Binding request values into simple and complex binding models.
- Validating binding models (chapter 16) · Validating binding models with DataAnnotations and displaying validation feedback.
- Views: Rendering the user interface (chapter 17) · Views as the server-rendered user interface.
- Introducing Razor templates (chapter 17) · Razor templates as the mechanism for generating HTML.
- Passing data to views (chapter 17) · Passing server-side data to Razor views.
- Binding complex types (chapter 16) · Complex binding models and their properties as request-binding targets.
Section by section
Introduction
This chapter introduces Tag Helpers as Razor features that generate and enhance server-rendered HTML, especially user-friendly forms that bind and validate data correctly.
- Tag Helper purpose: Explain what Tag Helpers are and how they customize or generate HTML in Razor templates using information from C# models.
Why it matters: Tag Helpers reduce repetitive form markup while connecting rendered HTML to your application models. - Form-model integration: Describe how form Tag Helpers help generate correct form element names and IDs from a C# model so submitted values can be model-bound back into a Razor Pages application.
Why it matters: Correct model-connected form markup lets user input return to the right C# properties without hand-written boilerplate. - Server-side rendering scope: Distinguish server-side Razor and Tag Helper rendering from frontend-framework rendering, and state that Tag Helpers cannot be used directly in Angular or React.
Why it matters: Knowing where Tag Helpers execute prevents trying to use Razor-only syntax in a client-side frontend framework. - Tag Helpers over HTML Helpers: Justify using Tag Helpers for new Razor templates while recognizing that legacy HTML Helpers remain available when converting older ASP.NET templates.
Why it matters: This helps you choose the modern HTML-generation syntax while understanding a migration path for older views.
Key terms: Tag Helpers, Razor, Razor templates, HTML, model binding, binding model, names, IDs, DataAnnotations, validation
18.1 Catering to editors with Tag Helpers
This section introduces Tag Helpers as HTML-like Razor features that connect server-side model metadata and values to generated form markup while remaining editor-friendly and simpler than WebForms controls.
- Tag Helper purpose: Explain what Tag Helpers are and how their asp-* attributes or custom elements modify the HTML element they are attached to while integrating server-side values into generated HTML.
Why it matters: Tag Helpers let Razor templates remain recognizable as HTML while incorporating data from the server. - Metadata-driven form generation: Describe how form Tag Helpers use a property named by asp-for, its type, and DataAnnotations metadata to generate labels, input values, id and name attributes, suitable input types, and validation errors.
Why it matters: Using model metadata reduces duplicated form markup and keeps rendered fields aligned with model binding and validation. - Editor-friendly Razor syntax: Explain why Tag Helpers were motivated by cross-platform editing: they blend into standard HTML syntax, making templates easier for standard HTML editors and people to read, while IDEs can still distinguish them and provide IntelliSense.
Why it matters: HTML-like syntax makes Razor form markup more approachable in editors beyond Visual Studio without losing tooling support. - Tag Helpers versus WebForms controls: Distinguish Tag Helpers from legacy ASP.NET Web Server controls by stating that Tag Helpers have no life cycle, only participate in rendering their attached element, cannot modify unrelated page content, and can have multiple helpers on one element.
Why it matters: This distinction prevents developers familiar with WebForms from assuming Tag Helpers carry the same broad scope and difficult life cycle.
Key terms: Tag Helpers, asp-*, Razor templates, PageModel, asp-for, DataAnnotations, view model, model binding, Validation Tag Helper, standard HTML syntax
18.2 Creating forms using Tag Helpers
This section introduces how form Tag Helpers generate model-bound HTML for Razor Pages while allowing developers to retain control over the resulting markup.
- Model-bound form generation: Explain how form Tag Helpers use properties exposed by a Razor Page's PageModel to generate form markup, including element names, IDs, values, form actions, and validation-related attributes. Describe the checkout page example in which a UserBindingModel is exposed as an Input property and referenced by Tag Helpers.
Why it matters: Model-bound Tag Helpers remove much of the repetitive HTML plumbing needed to build forms. - DataAnnotations form metadata: Describe how DataAnnotations on UserBindingModel properties serve both server-side model validation during a POST request and metadata for Razor Tag Helpers to generate appropriate form and validation markup.
Why it matters: Using the same annotations for validation and generated form metadata keeps the form aligned with the server-side model rules. - Tag Helper markup control: Explain that Tag Helpers are optional HTML-generation helpers: explicitly supplied attributes generally pass through to the output, and explicitly setting a normally generated attribute can override the helper's default, such as using type="color" instead of the default text input for a string property.
Why it matters: You can gain the productivity of generated form markup without losing control over required HTML or HTML5 input features.
Key terms: Tag Helpers, PageModel, UserBindingModel, Input property, DataAnnotations, model binding, model validation, metadata, data-* attributes, raw HTML
18.2.1 The Form Tag Helper
This section explains how the Form Tag Helper generates form submission URLs, supplies route and handler values, and adds antiforgery support for Razor Pages forms.
- Form Tag Helper activation: Describe how adding an asp- attribute to a form activates the FormTagHelper and causes it to generate the form's action URL. Explain that asp-page selects the Razor Page that receives the submitted form.
Why it matters: The Form Tag Helper lets Razor Pages generate submission URLs rather than hard-coding them in HTML. - Same-page post behavior: Explain that omitting asp-page makes a Razor Pages form post back to the URL that served it, which is commonly handled by the same Razor Page. State that method="post" must then be added manually, because the browser otherwise defaults the form to GET.
Why it matters: Using POST explicitly avoids accidentally sending form data with GET, which can create a security risk. - Route values and handlers: Describe how asp-route-* attributes supply route parameter values when the Form Tag Helper generates an action URL, such as asp-route-id for an {id} route parameter. Explain that asp-page-handler selects the Razor Page handler that receives the POST.
Why it matters: Route values and handler selection let a form submit to the precise page URL and operation it needs. - Antiforgery token generation: Explain that the Form Tag Helper generates a hidden __RequestVerificationToken input by default to support protection against cross-site request forgery attacks. State that asp-antiforgery="false" disables generation when necessary, while the hidden field alone is not the complete protection.
Why it matters: The automatically generated hidden token is an important part of protecting form submissions from CSRF attacks.
Key terms: Form Tag Helper, FormTagHelper, asp-page, action attribute, method="post", GET, POST, Razor Pages, asp-route-*, asp-route-id
18.2.2 The Label Tag Helper
This section shows how the Label Tag Helper generates accessible labels from PageModel properties and their display metadata.
- Label Tag Helper generation: Explain how the Label Tag Helper uses the asp-for attribute to generate a label's visible caption and for attribute from a PageModel property. Describe how a [Display] attribute supplies the caption text, while the property name is used when [Display] is absent.
Why it matters: It saves manual label markup while keeping labels tied to the model that supplies the form fields. - Label and control association: Describe how the generated for attribute identifies the ID of the form control that a label refers to, and why this association is important for accessibility. Explain that Label Tag Helper output works with IDs generated by other Tag Helpers.
Why it matters: Correctly associated labels let assistive technologies communicate which field a user is interacting with. - Nested properties and overrides: Describe how asp-for can reference a child object's property with dotted C# property syntax, such as a binding model exposed by the PageModel. State that manually supplied label content is preserved rather than overwritten, though following the generated conventions is generally easier to maintain.
Why it matters: This lets forms use structured binding models while retaining an escape hatch for exceptional label text.
Key terms: Label Tag Helper, asp-for, [Display], PageModel, for attribute, ID, accessibility, screen reader, Tag Helpers, child objects
18.2.3 The Input and Textarea Tag Helpers
This section shows how the Input and Textarea Tag Helpers generate correctly bound, formatted, and validated form controls from model-property metadata.
- Input type inference: Explain how the Input Tag Helper uses an asp-for property, its CLR type, and its DataAnnotations attributes to choose the generated HTML input type. Describe the Email property example, where a string with [EmailAddress] produces an email input rather than the default text input.
Why it matters: This lets you create appropriate form controls from your model instead of manually choosing and maintaining their HTML attributes. - Binding and validation markup: Describe how the Input Tag Helper generates id, name, value, and data-val-* attributes from a bound property. Explain that the name retains dotted property notation for model binding, while client-side validation attributes can be used by JavaScript validation libraries for immediate feedback.
Why it matters: Correct generated names and validation attributes make submitted form data bind correctly and give users faster feedback about invalid values. - Input formatting customization: Describe how asp-format or a [DisplayFormat] attribute controls the string representation placed in an input's value attribute. State that the Input Tag Helper has default formats but a developer can override the format or explicitly override the generated type when the defaults do not suit the application.
Why it matters: Formatting values deliberately prevents a form from showing model values in an unsuitable representation for users. - Textarea property rendering: Describe how the Textarea Tag Helper uses asp-for similarly to the Input Tag Helper, but renders the current property value between the textarea tags and adds data-val-* validation attributes.
Why it matters: It provides the same model-aware binding and validation benefits for multiline text controls.
Key terms: Input Tag Helper, asp-for, DataAnnotations, EmailAddress, input type, id, name, model binding, data-val-*, client-side validation
18.2.4 The Select Tag Helper
This section shows how to generate and bind single-select, multi-select, grouped, and optional-value HTML select controls with the Select Tag Helper.
- Select Tag Helper bindings: Describe how the Select Tag Helper uses asp-for to bind a select element to a PageModel property and asp-items to supply the available options as an IEnumerable<SelectListItem>. Explain that the model needs a property for the selected value or values and a separate options-list property.
Why it matters: These bindings let Razor generate select options while preserving and receiving the user's selection. - Single and multiple selections: Explain how a select element supports a drop-down or single-selection list box versus a multiselect list box. State that binding asp-for to an IEnumerable selected-values property causes the Select Tag Helper to add the multiple HTML attribute.
Why it matters: The bound property's shape determines whether a form can accept one choice or several choices. - Grouped select options: Describe how assigning each SelectListItem's Group property to a SelectListGroup produces optgroup elements in the rendered select list. Explain that the Razor select markup remains unchanged and ungrouped items render normally outside an optgroup.
Why it matters: Groups organize long option lists without requiring separate handwritten HTML markup. - No-selection options: Explain why a select list may need a blank or “not selected” option: otherwise a drop-down defaults to its first item and always has a value. Describe the two approaches of adding that option to the SelectListItems or writing an option with a blank Value attribute directly in Razor.
Why it matters: An explicit empty choice lets a form represent that the user has not made a selection.
Key terms: Select Tag Helper, asp-for, asp-items, SelectListItem, Value, Text, IEnumerable, MultiValues, multiple, Group
18.2.5 The Validation Message and Validation Summary Tag Helpers
This section shows how Validation Message and Validation Summary Tag Helpers display property-level and model-level validation errors in forms.
- Property validation messages: Describe how the Validation Message Tag Helper uses a <span> with asp-validation-for to display validation errors for one view-model property. Explain that it works for both client-side validation and server-side ModelState errors, and updates when client-side validation reruns after the user changes the input.
Why it matters: Users need an error message next to the field they must fix, regardless of whether validation happened in the browser or on the server. - Validation summary configuration: Explain how the Validation Summary Tag Helper uses a <div> with asp-validation-summary to render a list of ModelState errors for the form. Distinguish the None, ModelOnly, and All ValidationSummary values, especially that model-level errors require a summary to be visible.
Why it matters: A summary ensures users can see form-wide errors that cannot be attached to any one input field.
Key terms: Validation Message Tag Helper, asp-validation-for, ModelState, client-side validation, server-side validation, Validation Summary Tag Helper, asp-validation-summary, ValidationSummary, model-level errors, ModelOnly
18.3 Generating links with the Anchor Tag Helper
This section shows how the Anchor Tag Helper generates Razor Page links through routing instead of hardcoded href URLs.
- Anchor Tag Helper link generation: Explain how the Anchor Tag Helper generates an <a> element's href for a Razor Page by using routing. Describe using asp-page, and optionally asp-page-handler and asp-route-* attributes, to identify the destination page, handler, and route values.
Why it matters: Routing-generated links stay aligned with your application's routes without manually constructing URLs in views. - Anchor URL generation options: Describe the additional Anchor Tag Helper attributes that control generated URLs: asp-area for an area route value, asp-host for a host, and asp-protocol for HTTP or HTTPS. Explain that setting asp-host or asp-protocol produces an absolute URL rather than a relative one.
Why it matters: These options let a view generate links that target an area, a specific host, or a particular protocol when a normal relative link is insufficient. - Routing-based link maintenance: Justify using the Anchor Tag Helper instead of embedding hardcoded URLs in views. Explain that routing generates the URL from page and route information, reducing duplicated URL strings that would otherwise need updating across views.
Why it matters: Avoiding duplicated hardcoded URLs makes links less fragile when routes change.
Key terms: Anchor Tag Helper, asp-page, asp-page-handler, asp-route-*, Razor Page, routing, asp-area, asp-host, asp-protocol, absolute URL
18.4 Cache-busting with the Append Version Tag Helper
This section explains how the Append Version Tag Helper automatically cache-busts static assets so browsers receive changed files while still caching unchanged ones.
- Browser caching trade-off: Explain why browser caching is useful for mostly unchanged static assets but can cause users to keep outdated images, CSS, or JavaScript after a file changes.
Why it matters: You need caching for performance, but stale client-side files can make an updated application look broken. - Cache-busting query strings: Describe how changing a query string such as ?v=1 to ?v=2 makes a browser treat the URL as a new resource and request a fresh copy.
Why it matters: A versioned URL lets unchanged resources stay cached while ensuring that changed resources are fetched again. - Append Version Tag Helper: Describe how adding the asp-append-version attribute to a script, img, or link element loads the referenced file and appends a query-string hash based on its contents.
Why it matters: The Tag Helper removes the error-prone manual work of changing every asset URL whenever a file is updated.
Key terms: static assets, browser cache, cache-busting query string, query parameter, Append Version Tag Helper, asp-append-version, hash
18.5 Using conditional markup with the Environment Tag Helper
This section shows how to render environment-specific Razor markup declaratively with the Environment Tag Helper instead of an inline C# condition.
- Environment-specific markup: Describe why a Razor view might render different HTML in development, testing, and production environments, such as using readable assets during development or showing a testing banner that is absent in production.
Why it matters: Environment-specific markup lets the same application present useful development or testing cues without exposing them in production. - Environment Tag Helper usage: Explain how the EnvironmentTagHelper conditionally renders its enclosed markup based on the current hosting environment, and distinguish it from placing an equivalent C# if statement directly in a Razor template.
Why it matters: The Environment Tag Helper expresses environment-dependent UI in clean, HTML-like markup while producing the same conditional result as an inline Razor condition.
Key terms: development environment, production environment, testing environment, Razor templates, EnvironmentTagHelper, Tag Helper, hosting environment, declarative, C# markup
18.6 Summary
This summary recaps how built-in Tag Helpers generate model-bound forms, routed links, cache-aware assets, and environment-specific server-rendered HTML.
Where this is used later
- Creating a custom Razor Tag Helper (chapter 32) · Extends Razor with custom Tag Helpers.
- (chapter intro) (chapter 32) · The role of Tag Helpers in making Razor markup easier to author.
- The benefits of Razor Pages (chapter 19) · Building HTML forms with Tag Helpers.
- Protecting from cross-site request forgery (CSRF) attacks (chapter 29) · Forms and the Form Tag Helper provide the HTML form mechanism in which antiforgery fields are rendered.
- Building a custom validation attribute (chapter 32) · Custom validation attributes provide another way to produce validation errors that must be presented to users.
- Exploring the template in Solution Explorer (chapter 23) · Using the Anchor Tag Helper to generate links.
- Defending against cross-site scripting (XSS) attacks (chapter 29) · The consequences of serving outdated JavaScript or other assets help frame safe rendering and deployment of client-side resources.
- Printing environment information with a custom Tag Helper (chapter 32) · the Environment Tag Helper for conditionally rendering markup by environment
Concepts explained in this chapter
- validation summaryValidation Tag Helpers are ASP.NET Core Tag Helpers that render model-validation errors in Razor forms.
- Tag HelpersTag Helpers are ASP.NET Core components that add server-side processing behavior to HTML-like elements in Razor files.
- input tag helperThe Input Tag Helper is an ASP.NET Core Tag Helper that generates and formats HTML input elements from a bound property and its metadata.
- form tag helperThe Form Tag Helper is an ASP.NET Core Tag Helper that generates and configures HTML form elements from Razor attributes and routing data.
- asp-for attributeThe asp-for attribute is an ASP.NET Core Razor attribute that associates an HTML element with a model property for Tag Helper processing.
- label tag helperThe Label Tag Helper is an ASP.NET Core Tag Helper that generates a label's associated field reference and display caption from a bound property.
- client-side validationClient-side validation is validation performed in client software, typically a browser, before submitted data reaches the server.
- SelectListItemSelectListItem is an ASP.NET Core MVC data structure representing one option in a select list, including its value, text, and selection state.
- select tag helperThe Select Tag Helper is an ASP.NET Core Tag Helper that generates HTML select controls and their options from Razor model properties and item collections.
- cache bustingCache busting is a technique that changes a resource's cache identity when its contents change so clients retrieve the latest version.
- EnvironmentTagHelperEnvironmentTagHelper is a built-in ASP.NET Core Tag Helper that conditionally renders its element content for specified hosting environments.
- anchor tag helperThe Anchor Tag Helper is an ASP.NET Core Tag Helper that generates an anchor element's URL from Razor Page and routing attributes.
- data-val-* attributeA data-val-* attribute is an HTML attribute convention that encodes validation metadata for unobtrusive client-side validation libraries.
- textarea tag helperThe Textarea Tag Helper is an ASP.NET Core Tag Helper that generates textarea elements and populates them from a bound property.
- asp-items attributeThe asp-items attribute supplies the collection of SelectListItem objects from which a select control's option elements are generated.
- dropdownA select element is an HTML form control that presents one or more options for user selection.
- user binding modelA user binding model is an application-defined binding model containing user-related request data for a specific form or handler.
- server-side renderingServer-side rendering is the process of generating HTML on the server before sending it to a client.
- hash functionA hash is a deterministic compact value computed from data such that modifying the data normally changes the resulting value.
- GetEnumSelectListGetEnumSelectList is an ASP.NET Core HTML helper method that creates select-list items for the values of an enumeration type.
- SelectListGroupSelectListGroup is an ASP.NET Core MVC data structure representing a group of related options in a select list.
- cross-site request forgeryCross-site request forgery (CSRF) is an attack in which a victim's authenticated browser is induced to submit an unintended request to a trusted application.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
