Similar to this question, I am looking for a component to add tags to an object like in stackoverflow, meaning autocomplete text field for tags. I am either looking for a native component or a way to wrap a JS solution so that it can be used in blazor.
Another idea is a multi-select component with checkboxes like discussed here, but I do not really like the idea.
Ideally I would provide a list of all tags and bind to a list on an item for which the tags are being set.
Advertisement
Answer
Usually, it’s not right practice to share full code as SO is not a code sharing site and it’s generally asked What you have tried so far?. However since Blazor is a new technology thus beginners struggle with finding a good solution or a plugin on web to meet their requirement thus I’m considering this as an exception.
Now answer to your question Creating a new component for adding tags. You can use below solution that I created in one of the project I’m working on. This doesn’t require any JS and can be handled with C# only to create a Tag. You can also check the Blazor Fiddle solution in action that I have prepared for you on fiddle. Hope this is what you are looking for.
@using System; @using System.Collections.Generic; @using System.Linq; @using System.Text.RegularExpressions; <style> .suggestion-container { position: relative; } .tagsinput, .tagsinput * { box-sizing: border-box } .tagsinput { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap; background: #fff; font-size: 14px; line-height: 20px; color: #556270; padding: 5px 5px 0; border: 1px solid #e6e6e6; border-radius: 2px } .tagsinput.focus { border-color: #ccc } .tagsinput .tag { position: relative; background: #556270; display: block; max-width: 100%; word-wrap: break-word; color: #fff; padding: 5px 30px 5px 5px; border-radius: 2px; margin: 0 5px 5px 0 } .tagsinput .tag .tag-remove { position: absolute; background: 0 0; display: block; width: 30px; height: 30px; top: 0; right: 0; cursor: pointer; text-decoration: none; text-align: center; color: #ff6b6b; line-height: 30px; padding: 0; border: 0 } .tagsinput .tag .tag-remove:after, .tagsinput .tag .tag-remove:before { background: #ff6b6b; position: absolute; display: block; width: 10px; height: 2px; top: 14px; left: 10px; content: '' } .tagsinput .tag .tag-remove:before { -webkit-transform: rotateZ(45deg); transform: rotateZ(45deg) } .tagsinput .tag .tag-remove:after { -webkit-transform: rotateZ(-45deg); transform: rotateZ(-45deg) } .tagsinput div { -webkit-box-flex: 1; -webkit-flex-grow: 1; -ms-flex-positive: 1; flex-grow: 1 } .tagsinput div input { background: 0 0; display: block; width: 100%; font-size: 14px; line-height: 20px; padding: 5px; border: 0; margin: 0 5px 5px 0 } .tagsinput div input:focus { color: #495057; background-color: #fff; border-color: #80bdff; outline: 0; box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25); } .tagsinput div input.error { color: #ff6b6b } .tagsinput div input::-ms-clear { display: none } .tagsinput div input::-webkit-input-placeholder { color: #ccc; opacity: 1 } .tagsinput div input:-moz-placeholder { color: #ccc; opacity: 1 } .tagsinput div input::-moz-placeholder { color: #ccc; opacity: 1 } .tagsinput div input:-ms-input-placeholder { color: #ccc; opacity: 1 } </style> <div class="suggestion-container w-75"> <div id="@($"{Id}_tagsinput")" class="tagsinput"> @if (Tags != null && Tags.Any()) { @foreach (var tag in Tags) { <span class="tag"> <span class="tag-text">@tag</span> <span class="tag-remove" @onclick="() => DeleteTag(tag)" /> </span> } } <div id="@($"{Id}_addTag")"> <div class="@(IsContainSpecialCharacter ? "tag-tooltip" : string.Empty)"> <input id="@($"{Id}_tag")" class="tag-input" placeholder="Add tags" autocomplete="off" @bind-value="Value" @bind-value:event="oninput" @onkeyup="AddTags" /> @if (IsContainSpecialCharacter) { <div class="error-right d-inline-flex p-2"> <i class="oi oi-warning text-warning p-1"></i> <p class="text-left m-0 p-1">Special characters not allowed.</p> <i></i> </div> } </div> </div> </div> </div> @code{ private Guid Id => Guid.NewGuid(); protected string Value { get; set; } protected bool MenuVisibility { get; set; } protected bool IsContainSpecialCharacter { get; set; } protected List<string> Tags { get; set; } = new List<string>(); protected void AddTags(KeyboardEventArgs eventArgs) { IsContainSpecialCharacter = false; if (!String.IsNullOrEmpty(Value)) { if (eventArgs.Key.Equals("Enter")) { var regex = new Regex(@"[^a-zA-Z0-9s]"); if (!regex.IsMatch(Value)) { if (!Tags.Exists(t => t.Equals(Value, StringComparison.CurrentCultureIgnoreCase))) { Tags.Add(Value); } Value = string.Empty; } else { IsContainSpecialCharacter = true; } } } } protected void DeleteTag(string value) { if (String.IsNullOrEmpty(value)) return; var tag = Tags.FirstOrDefault(t => t == value); if (tag == null) return; Tags.Remove(tag); } }
P.S. What I’ve shared here is only a code snippet of building tags, it doesn’t not contain tags with autocomplete option as it would require time to create a full solution on fiddle with fake data. Thus I’m avoiding that due to time limitation.