Custom Tag Helper: Toggling Visibility On Existing HTML elements

A lot of times we need a way to toggle the visibility of an element based on some server-side values.  The most common example is if someone is logged in, show them more options than someone who is not logged in.

Option without Tag Helpers


@if (User.Identity.IsAuthenticated)
{
<div>
This should only be visible if you're logged in
</div>
}

view raw

Index.cshtml

hosted with ❤ by GitHub

This solution always felt a little dirty to me

What I’d like to do is to add an attribute off of div to toggle visibility.  So instead I’d like something that looks like this:


<div is-visible="User.Identity.IsAuthenticated">
This should only be visible if you're logged in
</div>

view raw

Index.cshtml

hosted with ❤ by GitHub

So let’s create a custom Tag Helper to do this

  • Create a TagHelpers folder in the root of your MVC project
  • Create a new class called VisibilityTagHelper
  • Copy and paste the super simple code below


// Add more target elements here on a new line if you want to target more than just div. Example: [HtmlTargetElement("a")] to hide/show links
[HtmlTargetElement("div")]
public class VisibilityTagHelper : TagHelper
{
// default to true otherwise all existing target elements will not be shown, because bool's default to false
public bool IsVisible { get; set; } = true;
// You only need one of these Process methods, but just showing the sync and async versions
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (!IsVisible)
output.SuppressOutput();
base.Process(context, output);
}
public override Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
if (!IsVisible)
output.SuppressOutput();
return base.ProcessAsync(context, output);
}
}

  • Go to /Views/_ViewImports.cshtml and add a line for all the TagHelpers in your project by doing @addTagHelper *,  .  Example below:


@addTagHelper *, WebApplication1

  • Build your project *this is important or you won’t get intellisense*
  • Start using it such as the example shown below (same as above)


<div is-visible="User.Identity.IsAuthenticated">
This should only be visible if you're logged in
</div>

view raw

Index.cshtml

hosted with ❤ by GitHub

  • That’s it!

 

Or view the GitHub Commit that makes this happen

I also have a repo, where the first two commits are just the initial commit with a File => New Project.  This 3rd commit outlines all the changes needed to make to get this to work if you’d rather learn via a Commit.

 

Breaking Down The Code

The code for the Visibility Tag Helper is pretty straight forward, but here’s a breakdown of it:

  • HtmlTargetElement
    • You first decorate your class with the HtmlTargetElement attribute to tell it that you’re targeting div’s.
      [HtmlTargetElement("div")]
    • You can target more than just divs by adding more attributes.
      [HtmlTargetElement("div")]
      [HtmlTargetElement("a")]
    • You could add the is-visible attribute to ALL elements by using *.  This could be quite handy
      [HtmlTargetElement("*")]
    • UPDATE: 10/4/2018 – Per Andrew’s comment below, you can have this target all elements like above, but skip going through this TagHelper rendering by saying only run it if they have the is-visible attribute.  This should save some perf as well as not give you purple tags in Visual Studio on all of your HTML elements.
    • [HtmlTargetElement("*", Attributes = "is-visible")]
  • Inherit from TagHelper.
    • Naming the TagHelper doesn’t matter, as we are choosing the HtmlTargetElement.  If we were making our own tag, then the tag would be based off of the name.
      public class VisibilityTagHelper : TagHelper
      
  • Add a property to store the visibility of the tag.
    • We need to default it to true, otherwise none of the HTML tags specified in the HtmlTargetElement will be visible, because booleans default to false.  THAT IS REALLY IMPORTANT.  The name will be kebab-cased which means each capital letter will be split by a dash.  Example IsVisible becomes is-visible when using the tag.
      public bool IsVisible { get; set; } = true;
      
  •   Override the Process method
    • If the tag is set to not IsVisible, then we need to supress the output which will not render the tag at all.  (Thanks to Damian Edwards for the tip about SuppressOutput())
      public override void Process(TagHelperContext context, TagHelperOutput output)
      {
          if (!IsVisible)
              output.SuppressOutput();
          base.Process(context, output);
       }
      
  • That’s about it!  Super simple.

 

Update 1/3/2017: As mentioned above – thanks to Damian Edwards for informing me of the output.SuppressOutput() method.  That made things simpler.

9 thoughts on “Custom Tag Helper: Toggling Visibility On Existing HTML elements

  1. I see you don’t monetize your page, don’t waste your traffic, you can earn additional cash
    every month because you’ve got hi quality content.
    If you want to know how to make extra money, search for:
    Boorfe’s tips best adsense alternative

  2. Thanks for the post. I tweaked HtmlTargetElement to include the attribute selector and now it only fires on the specific elements that have “is-visible” instead of every single element being rendered:

    [HtmlTargetElement(“*”, Attributes = “is-visible”)]

Leave a Reply