Using HTML Range Inputs with ASP.NET Core TagHelpers
By FoxLearn 2/27/2025 7:36:27 AM 22
However, it’s missing some controls, including the highly useful range input.
What is a Range Input?
The range input is commonly referred to as a “slider,” allowing users to select a value by sliding an indicator along a scale. The range input is defined by a minimum and maximum value, ensuring that users can only select valid values. Additionally, you can specify the step
attribute to control the increment between values, and you can add markers using a <datalist>
element to help users better understand the scale.
Building a TagHelper for Range Inputs
When working with ASP.NET Core MVC or Razor Pages, you'll typically have a model and a Razor view.
Page Model:
public class IndexModel(ILogger<IndexModel> logger) : PageModel { [BindProperty] public int Value { get; set; } public string? Message { get; set; } public void OnGet() { } public void OnPost() { Message = $"You selected {Value}!"; } }
Razor View:
@page @model IndexModel @{ ViewData["Title"] = "Home page"; } @if (Model.Message is not null) { <div class="alert alert-info"> @Model.Message </div> } <form method="post" asp-page="Index"> <div> <label class="form-label" asp-for="Value"></label> <input class="form-range" asp-for="Value" /> </div> <button type="submit" class="btn btn-primary"> Add </button> </form>
At this point, you’ll notice that the input type for the Value
field is text
instead of range
.
Adding a Range Attribute
First, let's define a custom attribute to handle both the Range
and Step
metadata.
public class CustomRangeAttribute : RangeAttribute { public CustomRangeAttribute(int minimum, int maximum) : base(minimum, maximum) { } public double Step { get; set; } = 1; }
Now, apply this custom attribute to the Value
property in your model:
[BindProperty, CustomRange(1, 5, Step = 1)] public int Value { get; set; }
Creating the Range Input TagHelper
Next, let's create a TagHelper that will detect the RangeAttribute
and configure the HTML input element accordingly.
using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Razor.TagHelpers; namespace Custom { [HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)] public class RangeInputTagHelper : TagHelper { private const string ForAttributeName = "asp-for"; private const string TypeAttributeValue = "range"; public override int Order { get; } = -999; [HtmlAttributeName(ForAttributeName)] public ModelExpression For { get; set; } public override void Process(TagHelperContext context, TagHelperOutput output) { var metadata = For.Metadata; if (metadata is { ContainerType: not null, PropertyName: not null }) { var attribute = metadata.ContainerType.GetProperty(metadata.PropertyName) ?.GetCustomAttributes(typeof(RangeAttribute), true) .FirstOrDefault(); if (attribute is RangeAttribute range) { output.Attributes.SetAttribute("type", TypeAttributeValue); output.Attributes.SetAttribute("min", range.Minimum); output.Attributes.SetAttribute("max", range.Maximum); if (range is CustomRangeAttribute rws) { output.Attributes.SetAttribute("step", rws.Step); } } } } } }
Registering the Custom TagHelper
To use our custom TagHelper, we need to register it in the _ViewImports.cshtml
file. Just add the following line:
@addTagHelper *, Custom
Adjusting the TagHelper Order
We set the Order
property of the RangeInputTagHelper
to -999
because the default InputTagHelper
has an order of -1000
. This ensures our custom TagHelper runs right after the original one, allowing us to apply additional functionality without overriding default behavior.
After implementing these changes, running the application will display a range slider input where the min
, max
, and step
values are correctly set. This approach allows you to extend ASP.NET Core’s built-in tag helpers and handle input types that are otherwise missing, like the range input.
You can use this same technique for other HTML5 input types that aren’t natively supported in ASP.NET Core, ensuring your server-side and client-side code stays in sync.