Search code examples
razorrazor-pages

How can I get Razor Pages to not render a space before my partial?


I'm trying to render a Razor partial between curved brackets, but it's including a space after the bracket and before the contents of the partial.

Quoted text ending with a space followed by a span

In this image I'm expecting "Complete: 146 / 147 ("<span>...</span>")". My Razor markup contains the following source:

<span class="todo">Complete: @count / @total (@await Html.PartialAsync("_ColoredPercentageSpan", percent))</span>

For completeness the contents of my partial includes this:

@model double

@{
    var color = Model switch
    {
        >= 1.0 => "text-primary",
        >= 0.8 => "text-success",
        >= 0.6 => "text-warning",
        _ => "text-danger",
    };
}

<span class="@color">@Model.ToString("P0")</span>

Is there something about the Razor engine that's including the space, or is a quirk of the HTML? I slightly suspect including the span inline is causing the problem, but the closing bracket seems to be correct.


Solution

  • Poul Bak is correct in his comment that removing white space from the partial will resolve the issue:

    @model double
    @{
        var color = Model switch
        {
            >= 1.0 => "text-primary",
            >= 0.8 => "text-success",
            >= 0.6 => "text-warning",
            _ => "text-danger",
        };
    }<span class="@color">@Model.ToString("P0")</span>
    

    However, for inline stuff like this, you should consider a tag helper if you need reuse or a simple local Razor function. Here's an example of a local function which is declared in the consuming page:

     @functions{
        private string GetCompletedColor(double value)
        {
            return value switch
            {
                >= 1.0 => "text-primary",
                >= 0.8 => "text-success",
                >= 0.6 => "text-warning",
                _ => "text-danger",
            };
        }
     }
    

    This is called as follows:

    <div class="vstack gap-1">
        <span class="">Issued: Aug 28, 2023</span>
        <span class="">Complete: 146 / 147  (<span class="@GetCompletedColor(percent)">@percent.ToString("P0")</span>)
    </div>
    

    Alternatively, create a simple tag helper:

    using Microsoft.AspNetCore.Razor.TagHelpers;
    
    namespace WebApplication3.TagHelpers;
    [HtmlTargetElement("percent-span")]
    public class PercentTagHelper : TagHelper
    {
        public double Percent { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            var color = Percent switch
            {
                >= 1.0 => "text-primary",
                >= 0.8 => "text-success",
                >= 0.6 => "text-warning",
                _ => "text-danger",
            };
            output.TagName = "span";
            output.Attributes.SetAttribute("class", color);
            output.Content.SetContent($"{Percent:P0}");
        }
    }
    

    Activate custom tag helpers for your app in _ViewImports.cshtml:

    @addTagHelper *, MyApp // name of your project containing the tag helper you built
    

    And then use it like this:

    <div class="vstack gap-1">
        <span class="">Issued: Aug 28, 2023</span>
        <span class="">Complete: 146 / 147  (<percent-span  percent="percent"></percent-span>)</span>
    </div>