Skip to content

Inputs

TagsInput

Bit.BlazorUI

The TagsInput turns free text into a list of short values: the user types a tag, confirms it with the Enter key (or with a separator character of your own), and it becomes a removable chip sitting in front of the input. It binds to a collection of strings, offers the known values through the browser's own suggestion list - and can be restricted to those values alone - splits pasted text over its separators so a comma separated list, or a column copied out of a spreadsheet, arrives as a whole row of tags, and keeps the entries in shape on the way in: trimming them, running them through a transformer of yours, capping their length and their number, and rejecting the ones that repeat, that are too short, that do not match a pattern or that a validator of yours turns down - every rejection reported with the rule that caused it rather than being swallowed. The chips form a proper accessible list: a single stop of the tab order that the arrow keys walk through, each carrying its position in the whole list, removable with Delete or Backspace as well as with its dismiss button, correctable in place with a double click or the F2 key, and movable by dragging it or with Alt and the arrow keys - with every addition, removal, edit, move and rejection announced to screen readers, and every browser default that would have got in the way held back. A long list folds away behind a chip that says how many are left, each chip can be styled by its own value, the whole component can be driven from code, and every change can be watched or called off before it happens. It comes in three sizes, three variants and the whole accent palette, carries a label, a described helper text, a prefix, a suffix, a tag counter and a clear button, posts its value as a single field in a plain HTML form, and takes part in an EditForm validation like any other input.

Usage

Every example is live. Open its code to see exactly what produced the component running underneath.

Basic

Type a word and press Enter: it becomes a chip in front of the input, and its dismiss button takes it back off. ReadOnly keeps the tags visible and navigable while refusing every change to them, so the dismiss buttons are not rendered at all, and IsEnabled="false" dims the whole field along with the tags in it.

Tag 1
Tag 2
Tag 1
Tag 2

Label

Label renders the caption above the field and ties it to the input, so clicking it puts the caret in there and screen readers announce it with the field. LabelTemplate replaces the text with markup of your own when a plain string is not enough. Combined with the inherited Required, the label carries the asterisk that marks the field as mandatory.

Description

Description renders a hint under the field, which the input references through its aria-describedby attribute, so it is announced along with the field rather than only being drawn. It is where the rules of the field belong: the accepted format, the number of tags allowed, the separator that splits them. DescriptionTemplate takes markup instead of a string, and is referenced exactly the same way.

Press Enter after each skill. Up to 5 of them.
Separate the addresses with a comma or a semicolon.

Placeholder

Placeholder is the hint shown while the list is still empty. Once there is at least one tag it would only compete with them for the width of the field, so it is dropped - unless a TagsPlaceholder is given, which is what keeps the invitation to add another one visible without repeating the whole sentence.

blazor

Variant

Variant decides how much of a frame the field carries: Outline (the default) draws a full rule around it, Fill paints it with a surface color and drops the rule, and Text keeps only an underline, for a field that should not outweigh the ones around it. NoBorder removes the frame altogether, for a field sitting on a surface that already provides one. It is the frame of the field alone; how the tags in it are painted is the TagVariant.

blazor
dotnet
blazor
dotnet
blazor
dotnet
blazor
dotnet

Tag variant

TagVariant decides how much of the Color the tags themselves are painted with: Fill (the default) fills every chip with it, the way a BitTag is filled, Outline leaves the chip unfilled and draws the color as its rule and its text, and Text keeps only the text in it, for tags that should not outweigh the field holding them. It is independent of the Variant, which is about the frame of the field rather than the tags in it, so the two combine freely.

blazor
dotnet
blazor
dotnet
blazor
dotnet

Separators

By default the Enter key is the only thing that turns the typed text into a tag. Separators adds characters that do the same: typing one of them commits whatever stands before it, and the character itself never reaches the input. A separator is any string at all - a single character such as a comma or a space, or a longer one such as ", ". The very same separators split a paste, so a comma separated list copied out of a spreadsheet or a mail client arrives as a whole row of tags in one go - each piece of it going through the same validation, so the ones that are refused are reported while the rest are still added. A pasted text spread over several lines is joined over the first separator on its way in, since a single line field would otherwise drop the line breaks and leave one run-on tag behind.

Try pasting: red,green;blue - or a column copied out of a spreadsheet.

Suggestions

Suggestions offers a set of known values while the user types, through the suggestion list the browser itself renders for a datalist - which is what keeps it reachable, positioned and announced on every platform without a popup of our own. Picking one only fills the input; it is the usual Enter (or a separator) that turns it into a tag, so every rule of the field still applies to it. The values already in the list are left out of the suggestions, unless Duplicates allows them back in, and so are all of them once the MaxTags ceiling leaves nothing to add. A datalist suggests rather than restricts, so free text is still accepted next to it; RestrictToSuggestions is what turns the suggestions into the whole of what the field accepts, rejecting anything else with the NotSuggested reason. What counts as one of the suggestions is decided by Comparison, and the tag that is stored is the suggestion rather than the spelling it was typed with - so with an OrdinalIgnoreCase comparison, typing BLAZOR adds blazor, and a list that has to be grouped or looked up later never holds two spellings of one value.

A catalogue of known values is written into the page in full, and rebuilt on every keystroke, so MaxSuggestions caps how many of them are offered at once: beyond it only the values holding what is being typed are kept, and only as many of those as it allows. It changes nothing about what the user is actually shown - the browser filters the list it is handed all over again - only about how much of a catalogue of thousands ever reaches the page.

Type a letter or two to see the list.
Anything that is not one of the suggestions is refused.
Only the five best matches are ever written into the page.

MaxTags

MaxTags caps how many tags the list may hold. Once the ceiling is reached every further tag is rejected with the MaxTags reason, which the OnInvalid callback receives - so the field can say why nothing happened instead of appearing to ignore the Enter key. A paste that would overflow the cap stops there rather than being rejected as a whole.

blazor
Tags: 1 / 3

Length limits

MaxLength caps the number of characters of each individual tag. It is a truncation rather than a rejection: the input stops accepting characters beyond it, and a pasted value longer than it is cut down to size instead of being thrown away - which matters for a paste, where throwing the twelfth character away is far better than throwing the whole list away. The little input that replaces a tag while it is corrected in place carries the cap natively, since there the limit of a tag is the limit of the whole field. MinLength works the other way round and does reject: a tag shorter than it never enters the list, and the rejection is reported with the MinLength reason. Both of them count the text after the trimming and the Transformer, so they measure exactly what would be added.

Typing beyond the tenth character does nothing.
Shorter entries are refused.

Pattern & Validator

Pattern is a regular expression that every tag has to match; an expression that cannot be compiled is ignored rather than breaking the field, and a match that runs away is timed out and treated as a failure. Validator covers what an expression cannot express - a lookup in a list of allowed values, a checksum, a rule that depends on the other tags - by taking a predicate instead. Both run after the trimming and the transformation, so they see exactly the text that would be added, and both report their rejection through OnInvalid.

Only well formed addresses are accepted.
Only blazor, react, vue and angular are allowed.

Transformer

Transformer normalizes the text of a tag before anything else is done with it, which is what keeps a list consistent whichever way its entries were typed: lower casing them, stripping a leading #, collapsing the whitespace inside them. It runs before the length, pattern, validator and duplicate checks, so all of them see the normalized text - which means #Blazor, blazor and BLAZOR all collapse into the same tag and the second of them is refused as a duplicate. An exception thrown out of it leaves the text untouched rather than breaking the field.

Lower cased, stripped of a leading # and of the whitespace inside.

Duplicates

A tag that is already in the list is refused by default, and the refusal is reported through OnTagExists as well as through OnInvalid. Duplicates lifts that rule for the lists where repetition means something. Which tags count as the same one is decided by Comparison: it is Ordinal by default, so Blazor and blazor are two different tags, while OrdinalIgnoreCase makes them one.

blazor
blazor

Editable tags

EditableTags lets a tag be corrected in place instead of having to be removed and typed again: double click a chip, or press Enter or F2 on the focused one, and it turns into a little input with its text selected. Enter commits the new text, Escape puts the old one back, and leaving the input commits it too. The text goes through the very same trimming, transformation and validation as a tag being added - except that the tag is not a duplicate of itself and the MaxTags ceiling cannot be reached, since the list does not grow. Committing an empty text removes the tag, and OnEdit receives the old and the new text and can call the change off. The Enter that commits the correction is held back from the form around the field exactly as the one that adds a tag is, and an input method composing a character keeps it as well, so a correction is never committed half way through a word.

blazor
dotnet
web
Press Enter to edit, or Delete to remove.

Clear button

ShowClearButton renders a button at the end of the field that empties the whole list along with the text left in the input, and raises OnClear with the tags it removed. It is not rendered while the field is read-only, disabled or already empty, and it stays out of the tab order - the Escape key pressed on the input being its keyboard equivalent. Escape takes back what is being typed before it takes anything else, though: while there is text in the input it only clears that text, and it is the second press, on the now empty input, that empties the list - since throwing a whole list of tags away over a half typed word is not an undo but a loss. OnBeforeClear runs first, whichever of the three emptied the field, and receives the whole list along with a Cancel flag - which is where a confirmation belongs, emptying a list of fifty tags by accident being exactly the mistake that is worth one. Pressing the button takes the button itself away with everything else, so the caret is handed back to the input rather than being dropped on the page; a clear that was called off leaves both exactly where they were.

blazor
dotnet
web
blazor
dotnet
web
Clearing is refused while there are more than two tags.

Counter

ShowCounter draws the number of tags under the field, at the end of the line the Description sits on, as a plain count or as count / MaxTags when there is a ceiling to reach. It is drawn rather than announced - the list of chips is what a screen reader counts, and every addition and removal is already spoken by the live region.

blazor
dotnet
blazor
dotnet
Press Enter after each tag.

Keyboard

The chips are a single stop of the tab order rather than one per tag, which the arrow keys then walk through: Left and Right (swapped in a right-to-left direction) move between them, Home and End jump to the two ends, Delete and Backspace remove the focused one and hand the focus to its neighbour, Enter and F2 open the inline edit when EditableTags is on, Alt with the arrows moves the tag when AllowReorder is, and Escape goes back to the input. Every one of those keys carries a browser default that is held back for it - Home and End would scroll the page away, Alt with an arrow would walk the whole document back through the history - so a gesture of the field never turns into a gesture of the browser. From the input, Backspace on an empty field removes the last tag (which NoBackspaceRemove turns off, and which BackspaceEditsLastTag turns from a removal into a correction, putting the text of that tag back into the input to be fixed and confirmed again rather than letting it simply disappear), and the arrow pointing backwards walks into the last chip. Tab commits the text left in the input instead of leaving it behind - unless NoAddOnTab is set - while Shift+Tab always walks straight out, so the field is never a trap. Losing the focus commits the text as well, which NoAddOnBlur turns off and ClearOnBlur turns into a discard, so a half typed word is not found again hours later in a field the user believes they finished with. Escape takes back the text being typed, and only empties the list on a second press, once there is nothing left to take back and ShowClearButton is on.

None of that is visible on a chip that looks like nothing but a word, so once the inline edit or the reordering is on, each tag is announced with a sentence saying which keys it answers to - TagAriaDescription being what replaces, localizes or silences it. Each chip also carries its own position in the whole list, so "the third of six" stays true even where MaxDisplayedTags has folded the other three away. And while an input method is composing a character (Chinese, Japanese, Korean), the Enter that picks a candidate out of the suggestion window is not treated as a confirmation - neither in the input nor in the inline edit - so a tag is never cut in half by it.

one
two
three
one
two
one
two
Backspace on the empty input takes the last tag back for correction; leaving the field throws away what was still being typed.

Reordering

AllowReorder lets a tag be moved within the list two equal ways. With a pointer, a chip can be picked up and dropped onto the one whose position it should take: the chip being carried is faded out and the one under the pointer is outlined, so the landing place is visible before the button is let go of. Without a pointer, focus a chip and hold Alt while pressing the left or right arrow to walk it one position at a time, or Alt+Home and Alt+End to send it to either end - which is what keeps the reordering usable on a touch screen and with a screen reader, where a drag is not. Either way the focus travels with the tag, so several steps can be taken in a row, and each move is announced along with the position the tag landed on. In a right-to-left direction the arrows are mirrored, exactly as they are for the plain navigation, and the browser's own Alt+arrow history navigation is held back so that reordering a tag never leaves the page.

OnReorder reports each move with the tag and the two positions it went between, which is what tells a consumer which tag moved and where to - the bound value alone would have to be diffed against its previous state to find that out. The order of the tags is part of the value, so a move is a change like any other: it is written back through @bind-Value and reported through OnChange as well.

first
second
third
fourth
Drag a chip onto another one, or focus one with Tab and hold Alt while pressing the arrow keys.
Press Alt with the arrow keys to move, or Delete to remove.

TagTemplate

TagTemplate replaces the text of every chip with markup of your own, the tag itself being the context. The chip around it - its background, its focus ring and its dismiss button - is still provided by the component, so a template only has to describe what goes inside.

blazor
dotnet

Binding

The value is the list of tags itself, bound two ways with @bind-Value. DefaultValue seeds an uncontrolled field, the one that is read through the OnChange callback rather than through a bound property. Note that removing the last tag leaves the value at null rather than at an empty list, which is what makes a plain [Required] annotation catch an empty field.

Tags: null
blazor
Tags: null

Events

OnBeforeAdd and OnBeforeRemove run before the list is changed and can call the change off by setting args.Cancel, which is the hook for a confirmation or for a rule that lives on the server. OnAdd receives every tag added in one go (a paste adds several of them at once), OnRemove the one that was taken off, OnInvalid the one that was refused along with the rule that refused it, and OnInput the text of the input as it is typed - which is what an external suggestion list is driven by. OnInput also reports the emptying the component does itself, when the text becomes a tag or the field is cleared, so a suggestion list of your own is never left filtering on a word that is already a chip. OnFocusIn, OnFocusOut and OnKeyDown report the plain input events on top of them.

Typing:
Last event:

Public API

The component can be driven from the outside as well: AddTagAsync and AddTagsAsync add through exactly the same pipeline as typing does (trimming, transformation, every validation rule and every callback), RemoveTagAsync and RemoveTagAtAsync take one off, MoveTagAsync moves one to another position exactly as a drag does - raising OnReorder with it, and without needing AllowReorder, since that parameter is what offers the gesture to the user rather than what permits the list to be reordered - EditTagAsync opens the inline edit of one (which does need EditableTags), SetInputTextAsync writes the text of the input - which is what fills the field from a suggestion list of your own driven by OnInput, and what empties it again once the pick has been turned into a tag - Clear empties the whole list, and FocusAsync puts the caret in the input. All of them do nothing while the field is disabled or read-only, and all of them go through the callbacks, the announcements and the validation that the equivalent gesture does, so nothing reaches the value by a back door.

blazor
Press Enter to edit, or Delete to remove.

Form submission

Enter is the key that confirms a tag, so it is held back from submitting the form around the field - which would otherwise post the form on the very keystroke meant to add a tag. CancelConfirmKeysOnEmpty hands it back once there is nothing left to confirm, so a field whose tags are already in place submits with Enter like any other input. Setting Name posts the whole list as a single field of a plain (non-EditForm) HTML form, the tags joined by the first separator, rather than posting whatever text happened to be left in the input.


Form submitted: False

Validation

Inside an EditForm the field takes part in the validation like any other input: it reports its changes to the EditContext, paints the error state, marks its input with aria-invalid and turns its description red. The value is the list itself, so the annotations that apply to it are the collection ones - [Required] catching the null of an empty field and [MinLength]/[MaxLength] counting its entries.

At least one tag is required.

Folding the tags away

A field that collects dozens of tags grows into a wall of chips that pushes everything below it off the screen. MaxDisplayedTags draws only the first few of them and folds the rest away behind a chip that says how many are left, which unfolds the list and folds it back again - so a tag that is not drawn is never a tag that cannot be reached, neither with the pointer nor with the keyboard, where the chip is a tab stop of its own. Only how much of the list is drawn changes: the value keeps every one of its tags, the counter keeps counting all of them, and the form keeps posting them. MoreTagsFormat and LessTagsText are what the two labels of the chip are written and localized with, and MoreTagsAriaLabelFormat what it is announced as - since "+3" read out on its own says nothing about what pressing it would do.

blazor
dotnet
web
The rest of the tags are one click away.
blazor
dotnet

Accessibility & localization

Nothing about a chip appearing, disappearing or changing place reaches a screen reader on its own - the list sits away from the caret the user is typing at - so the component says every one of those out loud through a polite live region: AddedAnnouncementFormat, AddedManyAnnouncementFormat, RemovedAnnouncementFormat, ClearedAnnouncementFormat, EditedAnnouncementFormat, MovedAnnouncementFormat and InvalidAnnouncementFormat. Most of them take {0} for the tag they are about - the move also taking {1} for the position it landed on and {2} for how many tags there are - and an empty string keeps that particular event silent. The two that stand for a whole batch count instead of naming: a pasted list and a cleared field take {0} as the number of tags, since reading fifty names out is not a confirmation but a wall, and the tags themselves are in the list to be walked through anyway.

The names of the parts follow the same idea: TagsAriaLabel names the list the chips form, TagAriaDescription is the sentence telling what the keyboard can do with the one just reached, DismissAriaLabelFormat and DismissTitle name the dismiss button of each tag, EditAriaLabelFormat the little input that replaces a tag while it is corrected, and ClearButtonAriaLabel the button that empties the whole field. Every one of them is a plain string, which is what makes the component translatable without a single line of CSS or markup of your own.

blazor
dotnet
Press Enter to edit, Delete to remove, or Alt with the arrow keys to move.
blazor
dotnet
Press Enter to rename this skill, or Delete to drop it.

Prefix & Suffix

Prefix and Suffix draw a short text inside the field, at its start and at its end, which is not part of the value: the To: of a recipients field, the unit a list of measurements is in. The prefix sits in front of the chips and the suffix after everything else, the clear button included, so it stays at the very end however much of the line the tags have taken. PrefixTemplate and SuffixTemplate take markup instead of a string, for an icon or a badge.

Neither of them ever reaches the value, and neither is announced with the field, so the meaning they carry has to be in the Label as well: a screen reader reading "Tags, edit" out of a field whose prefix says To: would otherwise have no idea what the tags are.

12
34
cm
blazor
dotnet

Styling each tag

Classes and Styles dress every chip alike, and TagTemplate only changes what is drawn inside one. GetTagClass and GetTagStyle are what tell one chip apart from the next: each of them receives a tag and returns the classes or the declarations that this particular chip should carry on top of the shared ones - the address that is not in the address book drawn in red, the value that came from a saved filter drawn in grey, the tag that is over budget outlined. They are called for every drawn tag on every render, so they belong to a lookup rather than to a computation, and an exception thrown out of one of them leaves that chip looking like all the others instead of breaking the field.

not-an-address
An address that is not well formed is drawn in red.
low
medium
high
Each level carries a color of its own.

Color

Color picks the color role the component carries. The tags are painted with it, as much of them as the TagVariant asks for, and so are the border and the focus ring of the focused field, so the color is visible at rest rather than only while the field is focused. The error state of a failing validation always wins over it on the field, which keeps an invalid field recognizable whatever its color is.

tag
tag
tag
tag
tag
tag
tag
tag
tag
tag
tag
tag
tag
tag
tag
tag
tag

External Icons

The dismiss button of each tag and the clear button of the field both take their icon either from the built-in Fluent UI set, through DismissIconName and ClearButtonIconName, or from any external icon library through DismissIcon and ClearButtonIcon, which take a BitIconInfo built by BitIconInfo.Fa (FontAwesome), BitIconInfo.Bi (Bootstrap Icons) or BitIconInfo.Css (any CSS classes at all). The BitIconInfo wins over the name when both are given.

blazor
dotnet
blazor
dotnet
blazor
dotnet

Size

Size scales the field, the chips and the text inside them together, so the whole thing stays proportionate at every size. Pick the one that matches the density of the surrounding form: the large size suits a standalone editor, the small one a filter tucked into a toolbar.

blazor
dotnet
blazor
dotnet
blazor
dotnet

Style & Class

Style and Class reach the root element only, while Styles and Classes reach every part of the component by name: the root, the label, the description, the counter, the input container, the prefix and the suffix, the wrapper of the tags, each tag and its text, the dismiss button and its icon, the chip that folds the tags away, the input, the little input that replaces a tag while it is corrected, and the clear button and its icon - plus the two state slots Focused (the field while its input has the focus) and FocusedTag (the chip the arrow keys are currently on).

Component's Style & Class:
blazor
blazor

Styles & Classes:
blazor
dotnet
Every part of the component has a slot of its own.
blazor
dotnet
Every part of the component has a slot of its own.

RTL

In a right-to-left direction the chips are laid out from right to left and the arrow keys swap along with them, so the key pointing at the visual left still walks towards the tag drawn there. The value itself keeps its logical order: the first chip is always the first tag of the list.

بلیزر
دات‌نت
با کلید Enter برچسب را ثبت کنید.
بلیزر
دات‌نت

API

Every parameter, public member, sub-class and enum this component exposes.

BitTagsInput parameters

Name Type Default value Description
AllowReorder bool false Lets a tag be moved within the list, either by dragging it onto the position it should take or from the keyboard: Alt with the arrow keys walks the focused tag one position at a time, and Alt with Home or End sends it to either end.
AddedAnnouncementFormat string? null The format of the message announced by screen readers when a tag is added, where {0} is the tag. The default is "{0} added.". An empty string keeps the addition from being announced.
AddedManyAnnouncementFormat string? null The format of the message announced by screen readers when several tags are added at once (a pasted list, most of the time), where {0} is how many of them there were. The default is "{0} tags added.". An empty string keeps the addition from being announced. A single tag is always announced with AddedAnnouncementFormat instead.
AutoFocus bool false Whether the input should receive focus on first render.
BackspaceEditsLastTag bool false Turns the Backspace pressed on an empty input from a removal into a correction: the last tag is taken off the list and its text is put back into the input, ready to be fixed and confirmed again. NoBackspaceRemove still wins over it, the key doing nothing at all then.
CancelConfirmKeysOnEmpty bool false When true, pressing Enter while the input is empty does not suppress the event, allowing it to propagate (e.g., to submit a parent form).
Classes BitTagsInputClassStyles? null Custom CSS classes for different parts of the tags input.
ClearButtonAriaLabel string? null Accessible label of the clear button, for the benefit of screen readers and of localization. The default is "Clear all tags".
ClearButtonIcon BitIconInfo? null Gets or sets the icon of the clear button using custom CSS classes for external icon libraries. Takes precedence over ClearButtonIconName when both are set.
ClearButtonIconName string? Clear Gets or sets the name of the icon of the clear button from the built-in Fluent UI icons.
ClearButtonTitle string? null The tooltip of the clear button, which is what the pointer reads rather than the screen reader. It falls back to the ClearButtonAriaLabel and then to "Clear all tags".
ClearedAnnouncementFormat string? null The format of the message announced by screen readers when every tag is removed at once, where {0} is how many of them there were. The default is "{0} tags removed.". An empty string keeps the clearing from being announced.
ClearOnBlur bool false Throws away whatever text is still sitting in the input when the field loses the focus. It runs after the text has had its chance to become a tag, so on its own it only takes away what was refused; paired with NoAddOnBlur it makes leaving the field cancel what was being typed.
Color BitColor? null The color role of the tags input (Primary by default). It is carried by the tags themselves, the way a BitTag carries it, and by the border and the focus ring of the focused field. How much of it the tags are painted with is decided by the TagVariant.
Comparison StringComparison StringComparison.Ordinal The string comparison used to tell one tag from another, which is what decides whether a tag is a duplicate of one that is already in the list.
Description string? null A hint rendered under the field, referenced by the input through its aria-describedby attribute so it is announced along with the field.
DescriptionTemplate RenderFragment? null A custom template rendered in place of the Description, referenced by the input through its aria-describedby attribute just the same.
DismissAriaLabelFormat string? null The format of the accessible label of the dismiss button of each tag, where {0} is the tag. The default is "Remove {0}".
DismissIcon BitIconInfo? null Gets or sets the icon for the dismiss button using custom CSS classes for external icon libraries. Takes precedence over DismissIconName when both are set.
DismissIconName string? Cancel Gets or sets the name of the icon for the dismiss button from the built-in Fluent UI icons.
DismissTitle string? null The title (tooltip) of the dismiss button of each tag. The default is "Remove".
Duplicates bool false Whether duplicate tags are allowed. Which tags count as duplicates of one another is decided by the Comparison.
EditableTags bool false Lets a tag be corrected in place: double clicking a tag (or pressing Enter or F2 on the focused one) turns it into a little input, Enter commits the new text and Escape puts the old one back. Committing an empty text removes the tag.
EditAriaLabelFormat string? null The format of the accessible label of the little input that replaces a tag while it is being edited in place, where {0} is the tag. The default is "Edit {0}".
EditedAnnouncementFormat string? null The format of the message announced by screen readers when a tag is edited, where {0} is the tag as it now reads. The default is "{0} updated.". An empty string keeps the edit from being announced.
GetTagClass Func<string, string?>? null A function returning extra CSS classes for a single tag, which is what tells one chip apart from the next. It is called for every drawn tag on every render, so it should be a lookup rather than a computation, and the classes are added to those the Classes give every chip alike.
GetTagStyle Func<string, string?>? null A function returning extra inline CSS styles for a single tag, the counterpart of GetTagClass. It is appended after the Tag and FocusedTag of the Styles, so it wins over both.
InvalidAnnouncementFormat string? null The format of the message announced by screen readers when a tag is rejected, where {0} is the tag. The default is "{0} was not added.". An empty string keeps the rejection from being announced.
Label string? null The label displayed above the input.
LabelTemplate RenderFragment? null A custom template for the label.
LessTagsText string? null The label of the chip that folds the tags back once MaxDisplayedTags unfolded them. The default is "Show less".
MaxDisplayedTags int 0 The number of tags drawn before the rest of them are folded away behind a chip that says how many are left, which unfolds the list and folds it back. Only how much of the value is drawn changes, never the value itself. 0 means all of them.
MaxLength int 0 The maximum number of characters allowed for each individual tag. Text beyond it is truncated rather than rejected. 0 means no limit.
MaxSuggestions int 0 The number of values the suggestion list is allowed to offer at once. Beyond this ceiling only the values that hold what is being typed are offered, and only as many of them as it allows, which is what keeps a catalogue of thousands from being written into the page in full on every keystroke. 0 means all of them.
MaxTags int 0 The maximum number of tags allowed. Once it is reached, further tags are rejected with the MaxTags reason. 0 means no limit.
MinLength int 0 The minimum number of characters a tag has to hold to be accepted. Shorter ones are rejected with the MinLength reason. 0 means no limit.
MoreTagsFormat string? null The format of the label of the chip that stands for the tags MaxDisplayedTags folded away, where {0} is how many of them there are. The default is "+{0}".
MoreTagsAriaLabelFormat string? null The format of the accessible label of that same chip, where {0} is how many tags are folded away. The default is "Show {0} more tags", since "+3" read out on its own says nothing about what pressing it would do.
MovedAnnouncementFormat string? null The format of the message announced by screen readers when a tag is moved with AllowReorder, where {0} is the tag, {1} its new one based position and {2} the number of tags. The default is "{0} moved to position {1} of {2}.".
NoAddOnBlur bool false Stops the text left in the input from being committed as a tag when the field loses the focus.
NoAddOnTab bool false Stops the Tab key from committing the text left in the input, leaving it to do nothing but move the focus.
NoBackspaceRemove bool false Stops the Backspace key from removing the last tag when the input is empty.
NoBorder bool false Removes the default border of the tags input.
NoTrim bool false Keeps the leading and trailing whitespace of a tag instead of trimming it away.
OnAdd EventCallback<IReadOnlyList<string>> Callback for when one or more tags are added. Receives the list of all newly added tags.
OnBeforeAdd EventCallback<BitTagsInputBeforeArgs> Callback invoked before a tag is added. Set args.Cancel = true to cancel the add.
OnBeforeRemove EventCallback<BitTagsInputBeforeArgs> Callback invoked before a tag is removed. Set args.Cancel = true to cancel the remove.
OnBeforeClear EventCallback<BitTagsInputClearArgs> Callback invoked before every tag is removed at once, by the clear button, the Escape key or the Clear method, carrying the whole list that is about to go. Set args.Cancel = true to leave it as it is.
OnClear EventCallback<IReadOnlyList<string>> Callback for when every tag is removed at once, by the clear button or by the Clear method. It receives the tags that were removed.
OnEdit EventCallback<BitTagsInputEditArgs> Callback invoked when an inline edit of a tag is about to be committed, carrying both the old and the new text. Set args.Cancel = true to leave the tag as it was.
OnFocusIn EventCallback<FocusEventArgs> Callback for when the input receives focus.
OnFocusOut EventCallback<FocusEventArgs> Callback for when the input loses focus.
OnInput EventCallback<string> Callback for when the text of the input changes, which is what an external suggestion list is driven by.
OnInvalid EventCallback<BitTagsInputInvalidArgs> Callback for when a tag is rejected, carrying the tag along with the rule that rejected it.
OnKeyDown EventCallback<KeyboardEventArgs> Callback for when a key is pressed down on the input. It is invoked for every key, including the ones the component handles itself.
OnRemove EventCallback<string> Callback for when a tag is removed.
OnReorder EventCallback<BitTagsInputReorderArgs> Callback for when a tag is moved within the list with AllowReorder, carrying the tag along with the positions it left and took.
OnTagExists EventCallback<string> Callback fired when a duplicate tag is attempted and Duplicates is false.
Pattern string? null A regular expression that every tag has to match to be accepted. An unusable expression is ignored rather than breaking the input.
Placeholder string? null The placeholder text of the input, shown while there is no tag in the list.
Prefix string? null A short text drawn at the start of the field, in front of the tags, which is not part of the value. Since it never reaches the value, the label of the field has to say what it means on its own for a screen reader.
PrefixTemplate RenderFragment? null A custom template drawn in place of the Prefix.
RemovedAnnouncementFormat string? null The format of the message announced by screen readers when a tag is removed, where {0} is the tag. The default is "{0} removed.". An empty string keeps the removal from being announced.
RestrictToSuggestions bool false Turns the Suggestions into the whole of what the field accepts: a tag that is not one of them is rejected with the NotSuggested reason, which is what a datalist on its own cannot do since it suggests rather than restricts.
Separators IEnumerable<string>? null The character(s) that turn the typed text into a tag on top of the Enter key, which is the only one there is by default. The very same separators split a pasted list into a tag each, and a pasted text holding line breaks is joined over the first of them before it is split.
ShowClearButton bool false Whether to render a button that removes every tag at once. It stays out of the tab order, the Escape key being its keyboard equivalent.
ShowCounter bool false Whether to render the number of tags under the field, next to the Description, as a plain count or as "count / MaxTags" when there is a ceiling to reach.
Size BitSize? null The size of the tags input.
Suggestions IEnumerable<string>? null The values offered to the user while typing, through the suggestion list the browser itself renders for a datalist. Picking one fills the input; the usual Enter (or a separator) turns it into a tag, so every validation rule still applies. Values already in the list are left out unless Duplicates allows them back in, and all of them are once the MaxTags ceiling is reached. See RestrictToSuggestions to make them the only accepted values.
Styles BitTagsInputClassStyles? null Custom CSS styles for different parts of the tags input.
Suffix string? null A short text drawn at the end of the field, after everything else, which is not part of the value. Since it never reaches the value, the label of the field has to say what it means on its own for a screen reader.
SuffixTemplate RenderFragment? null A custom template drawn in place of the Suffix.
TagTemplate RenderFragment<string>? null A custom template for rendering each tag.
TagAriaDescription string? null The sentence announced after each tag, telling what the keyboard can do with the one that has just been reached. It defaults to a sentence built from what the component was actually given (the inline edit, the reordering), and is left out entirely when neither is on. An empty string keeps it from being rendered at all.
TagsAriaLabel string? null The accessible name of the list the tags form, which is what a screen reader announces before walking through them. The default is "Tags".
TagsPlaceholder string? null The placeholder text of the input shown once there is at least one tag in the list, where the Placeholder would otherwise be replaced by nothing at all.
TagVariant BitVariant? null How much of the Color the tags are painted with: Fill (the default) fills each chip with it, the way a BitTag is filled, Outline leaves the chip unfilled and draws the color as its rule and its text, and Text keeps only the text in it. It is independent of the Variant, which is about the frame of the field rather than the tags in it.
Transformer Func<string, string>? null A function applied to the text of a tag before anything else is done with it, which normalizes the tags of a list that has to stay consistent. It runs before every validation rule.
Validator Func<string, bool>? null A predicate every tag has to satisfy to be accepted, for the rules a regular expression cannot express. Returning false rejects the tag with the Validator reason.
Variant BitVariant? null The visual variant of the field: an outline (the default), a filled surface, or only an underline.

BitTagsInput public members

Name Type Default value Description
InputElement ElementReference The ElementReference to the input element of the BitTagsInput.
FocusAsync ValueTask Gives focus to the input element of the BitTagsInput.
AddTagAsync Task Adds a tag through exactly the same pipeline as typing it does: the trimming, the Transformer, every validation rule and every callback included. It does nothing while the component is disabled or read-only.
AddTagsAsync Task Adds several tags at once, exactly as pasting a separated list of them does. The rejected ones are reported through OnInvalid while the rest are still added.
RemoveTagAsync Task Removes the first tag equal to the given one (per the Comparison), exactly as its dismiss button does.
RemoveTagAtAsync Task Removes the tag sitting at the given index.
MoveTagAsync Task Moves the tag sitting at the given index to another one, exactly as dragging it there or walking it with Alt and the arrow keys does, raising OnReorder along with it. Unlike the gestures, it does not require AllowReorder.
EditTagAsync Task Opens the inline edit of the tag sitting at the given index, exactly as double clicking it does. It requires EditableTags.
SetInputTextAsync Task Sets the text of the input, which is what fills the field from a suggestion list of your own driven by OnInput - and what empties it again once the pick has been turned into a tag. The MaxLength is applied to it and OnInput is raised with the text that was kept.
Clear Task Removes all tags along with the text left in the input, and raises OnClear with the tags that were removed.

BitInputBase parameters

Name Type Default value Description
DefaultValue TValue? null The default value of the input to be used in uncontrolled mode (i.e. when the Value is not bound), typically used alongside the OnChange callback.
DisplayName string? null Gets or sets the display name for this field.
InputHtmlAttributes IReadOnlyDictionary<string, object>? null Gets or sets a collection of additional attributes that will be applied to the created element.
Name string? null Gets or sets the name of the element. Allows access by name from the associated form.
NoValidate bool false Disables the validation of the input.
OnChange EventCallback<TValue?> Callback for when the input value changes.
ReadOnly bool false Makes the input read-only.
Required bool false Makes the input required.
Value TValue? null Gets or sets the value of the input. This should be used with two-way binding.

BitInputBase public members

Name Type Default value Description
InputElement ElementReference The ElementReference of the input element.
FocusAsync() () => ValueTask Gives focus to the input element.
FocusAsync(bool preventScroll) (bool preventScroll) => ValueTask Gives focus to the input element.

BitComponentBase parameters

Name Type Default value Description
AriaLabel string? null Gets or sets the accessible label for the component, used by assistive technologies.
Class string? null Gets or sets the CSS class name(s) to apply to the rendered element.
Dir BitDir? null Gets or sets the text directionality for the component's content.
ForceAnimation bool false Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested.
HtmlAttributes Dictionary<string, object> new Dictionary<string, object>() Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters.
Id string? null Gets or sets the unique identifier for the component's root element.
IsEnabled bool true Gets or sets a value indicating whether the component is enabled and can respond to user interaction.
Style string? null Gets or sets the CSS style string to apply to the rendered element.
TabIndex string? null Gets or sets the tab order index for the component when navigating with the keyboard.
Visibility BitVisibility BitVisibility.Visible Gets or sets the visibility state (visible, hidden, or collapsed) of the component.

BitComponentBase public members

Name Type Default value Description
UniqueId Guid Guid.NewGuid() Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed.
RootElement ElementReference Gets the reference to the root HTML element associated with this component.

BitTagsInputBeforeArgs properties

Arguments passed to the OnBeforeAdd and OnBeforeRemove callbacks.

Name Type Default value Description
Tag string string.Empty The tag text being added or removed.
Cancel bool false Set to true to cancel the add or remove operation.

BitTagsInputInvalidArgs properties

Arguments passed to the OnInvalid callback, describing the tag that was rejected along with the rule that rejected it.

Name Type Default value Description
Tag string string.Empty The tag text that was rejected, after the trimming and the transformation were applied to it.
Reason BitTagsInputInvalidReason BitTagsInputInvalidReason.None The rule that rejected the tag.

BitTagsInputEditArgs properties

Arguments passed to the OnEdit callback, describing an inline edit of a tag that is about to be committed.

Name Type Default value Description
Tag string string.Empty The tag as it stands in the list, before the edit.
NewTag string string.Empty The text the tag is about to become, after the trimming and the transformation were applied to it.
Cancel bool false Set to true to cancel the edit, leaving the tag as it was.

BitTagsInputClearArgs properties

Arguments passed to the OnBeforeClear callback, describing the whole list that is about to be emptied.

Name Type Default value Description
Tags IReadOnlyList<string> [] The tags that are about to be removed.
Cancel bool false Set to true to cancel the clear, leaving every tag in the list.

BitTagsInputReorderArgs properties

Arguments passed to the OnReorder callback, describing a tag that was moved within the list.

Name Type Default value Description
Tag string string.Empty The tag that was moved.
OldIndex int 0 The zero based position the tag was moved from.
NewIndex int 0 The zero based position the tag was moved to.

BitTagsInputClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root element of the tags input.
Focused string? null Custom CSS classes/styles for the focus state of the tags input.
Label string? null Custom CSS classes/styles for the label of the tags input.
InputContainer string? null Custom CSS classes/styles for the input container of the tags input.
Prefix string? null Custom CSS classes/styles for the prefix of the tags input.
Suffix string? null Custom CSS classes/styles for the suffix of the tags input.
TagsContainer string? null Custom CSS classes/styles for the element that wraps the rendered tags.
Tag string? null Custom CSS classes/styles for each tag element.
FocusedTag string? null Custom CSS classes/styles for the tag element that currently has the keyboard focus.
TagText string? null Custom CSS classes/styles for the tag text.
DismissButton string? null Custom CSS classes/styles for the dismiss button of each tag.
DismissIcon string? null Custom CSS classes/styles for the dismiss icon of each tag.
ToggleButton string? null Custom CSS classes/styles for the chip that stands for the tags MaxDisplayedTags folded away, which unfolds the list and folds it back.
Input string? null Custom CSS classes/styles for the text input element.
EditInput string? null Custom CSS classes/styles for the little input that replaces a tag while it is being edited in place.
Counter string? null Custom CSS classes/styles for the counter of the tags input.
ClearButton string? null Custom CSS classes/styles for the clear button of the tags input.
ClearIcon string? null Custom CSS classes/styles for the clear icon of the tags input.
Description string? null Custom CSS classes/styles for the description (helper text) of the tags input.

BitIconInfo properties

Name Type Default value Description
Name string? null Gets or sets the name of the icon.
BaseClass string? null Gets or sets the base CSS class for the icon. For built-in Fluent UI icons, this defaults to "bit-icon". For external icon libraries like FontAwesome, you might set this to "fa" or leave empty.
Prefix string? null Gets or sets the CSS class prefix used before the icon name. For built-in Fluent UI icons, this defaults to "bit-icon--". For external icon libraries, you might set this to "fa-" or leave empty.

BitTagsInputInvalidReason enum

Name Value Description
None 0 No reason was given, which is what an uninitialized value stands for rather than an actual rule.
Duplicate 1 The tag is already in the list and duplicates are not allowed.
MaxTags 2 The list already holds the maximum number of tags.
MinLength 3 The tag is shorter than the minimum length.
Pattern 4 The tag does not match the required pattern.
Validator 5 The tag was rejected by the custom validator.
NotSuggested 6 The tag is not one of the suggestions, which RestrictToSuggestions made the only accepted values.

BitVariant enum

Name Value Description
Fill 0 Fill styled variant.
Outline 1 Outline styled variant.
Text 2 Text styled variant.

BitSize enum

Name Value Description
Small 0 The small size.
Medium 1 The medium size.
Large 2 The large size.

BitColor enum

Name Value Description
Primary 0 Primary general color.
Secondary 1 Secondary general color.
Tertiary 2 Tertiary general color.
Info 3 Info general color.
Success 4 Success general color.
Warning 5 Warning general color.
SevereWarning 6 SevereWarning general color.
Error 7 Error general color.
PrimaryBackground 8 Primary background color.
SecondaryBackground 9 Secondary background color.
TertiaryBackground 10 Tertiary background color.
PrimaryForeground 11 Primary foreground color.
SecondaryForeground 12 Secondary foreground color.
TertiaryForeground 13 Tertiary foreground color.
PrimaryBorder 14 Primary border color.
SecondaryBorder 15 Secondary border color.
TertiaryBorder 16 Tertiary border color.

BitVisibility enum

Name Value Description
Visible 0 The content of the component is visible.
Hidden 1 The content of the component is hidden, but the space it takes on the page remains (visibility:hidden).
Collapsed 2 The component is hidden (display:none).

BitDir enum

Name Value Description
Ltr 0 Ltr (left to right) is to be used for languages that are written from the left to the right (like English).
Rtl 1 Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic).
Auto 2 Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element.

Feedback

Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.