Skip to content

Tag input โ€‹

A multi-value tag entry with optional autocomplete suggestions, validation states, max-tags limit, and slot-overridable label/helper. Tags are added with Enter, , or Tab, and removed with ร— or Backspace on an empty input. Toggle Vue / CSS to switch the live demo and source together.

Basic โ€‹

Default tag input that accepts custom values.

Vue SFC

Sizes โ€‹

Small, medium and large.

Vue SFC

Variants โ€‹

outlined, filled and underlined.

underlined focuses with a soft glow under the line rather than a ring around the field โ€” tune it with --mono-tag-input-underline-glow (default 0 5px 6px -6px).

The tag chips follow the variant: outlined โ†’ soft chips, filled โ†’ solid chips (a soft chip would disappear into the tinted field), underlined โ†’ outline chips. Pin a skin with chip.

Vue SFC

Colors โ€‹

All built-in color variants. The tag chips are tinted with the same color โ€” pin them to a different one with chip.

Vue SFC

Chips โ€‹

The tags are mono-chip markup, configured as one object so every chip prop is reachable:

vue
<mono-tag-input :chip.prop="{ size: 'md', shape: 'rounded', dot: true }" />

chip takes size, color, variant, shape, dot, closeLabel and cssClass โ€” the same names and values as the chip component. Keys you leave out follow the control rather than a fixed default: color tracks the control's color (and any --mono-tag-input-focus-color override), and variant tracks the skin mapping above. Setting color pins the chips and stops that tracking, so a success field can carry neutral tags.

Static HTML can pass the same object as a JSON attribute: chip='{"size":"md","dot":true}'.

Vue SFC

States โ€‹

Disabled, readonly and required.

Vue SFC

Validation โ€‹

valid, invalid and warning states with messages.

Vue SFC

Suggestions โ€‹

Autocomplete dropdown driven by an items array.

Vue SFC

Keyboard โ€‹

Focusing the field opens the panel and highlights the first suggestion, so โ†‘ / โ†“ move from there and Enter adds the highlighted one as a tag. The highlight scrolls into view on long lists, and is drawn as a leading bar on the item's left edge โ€” the background is reserved for a checked/selected suggestion, and the items already carry their own bottom dividers. Tune it with --mono-tag-input-cursor-width (default 3px) and --mono-tag-input-cursor-color.

open(), close(), toggle() and isOpen are public, mirroring <mono-select>, so the panel can be driven from outside (that's how the data grid opens it on Enter when a tag-input is an inline cell editor).

Max tags โ€‹

Limit how many tags can be added.

Vue SFC

Slots โ€‹

Custom label and helper content via named slots.

Vue SFC

Event log โ€‹

Live log of mno-add, mno-remove, mno-clear and mno-change.

Vue SFC

Customized โ€‹

Override per-element styling with cssClass (Vue) or utility classes (CSS).

Vue SFC

Custom keys โ€‹

Use key-value and display-value to feed natural-shape items (for example { id, name }) without pre-mapping. key-value names the property stored in each tag of modelValue; omit it to store the whole item object. display-value is either a property name (string) or a (item) => string function โ€” when unset it falls back to item.label.

Without key-value each tag is the whole item, and tags are matched by identity โ€” that is what decides whether clicking an option selects or de-selects it. A reactive wrapper around an item is fine (the tag input compares raw targets), but an item rebuilt between renders โ€” a refetch, a structuredClone, a JSON round trip โ€” is a different object and would be added as a second tag. Pass key-value whenever items are re-created.

Vue SFC

DataSource (devextreme) โ€‹

Bind a live devextreme DataSource with :data-source.prop. Suggestions come straight from the source, typing filters the loaded set client-side, and load-more="scroll" pages it one chunk at a time (here pageSize: 5). :immediate.prop="true" loads the first page on attach. This example builds the source with mono-utils' monoOdataFetch against a public OData endpoint (baseUrl, no configBaseUrl). Bind with .prop and use key-value / display-value to map the server fields.

Checkable + max โ€‹

Add checkable for a checkbox multi-select: each suggestion row shows a checkbox (reusing mono-checkbox's styling), selected rows stay in the list checked instead of disappearing, and the dropdown stays open so you can tick several. Chips reuse mono-chip styling. The max prop caps how many chips show inline โ€” the rest collapse into a clickable "+N more" chip whose dropdown lists them. Works with a raw items array (shown here) and a bound DataSource alike.

Vue SFC

Search the server โ€‹

Typing filters loaded suggestions; with a bound DataSource and search-value set, it queries the server (debounced) so you can tick matches from the whole dataset. A plain items array filters client-side.

Search expressions โ€‹

search-value is not limited to top-level field names. It takes the same grammar the data grid uses, as an array or as a comma-separated string โ€” the two are equivalent, so plain HTML loses nothing:

html
search-value="Company.Name,Transaction.[*].Price,*.[*].*"
ts
:search-value.prop="['Company.Name', 'Transaction.[1].Name', 'Transaction.[*].Price', '*']"

An entry can be:

EntryMatches
Namaa top-level field
Company.Namea nested field
Transaction.[1].Nameone array element
Transaction.[*].Nameany element of the array
*every top-level field
Company.*every field of Company
*.*every field of every nested object
*.[*].*every field of every array element

Patterns read literally, segment by segment โ€” '*' covers the top level only, so pair it with '*.*' / '*.[*].*' to reach deeper. A field named explicitly always wins over a pattern, in either order, and is searched exactly once.

In the array form an entry may also be a { field, custom } clause builder, for a column contains can't search โ€” a boolean, or a code the user never types. Return null to opt the column out of a given term:

ts
:search-value.prop="[
  '*',
  { field: 'Active', custom: ({ field, value }) => `${field} eq ${value === 'yes'}` },
]"

Setting search-value explicitly means it alone decides what is searched.

Leave it off and the default is '*' โ€” every top-level field of an option โ€” so searching works without naming anything. display-value (when it's a string) and key-value stay in the list beside it, and the rendered display text and each option's description are matched too.

Two caveats on a bound DataSource: a * pattern is resolved against the rows already loaded, so it can only see fields present in that sample; and it only emits clauses for string columns, because contains(Price,'x') is not valid OData. That is exactly why display-value / key-value remain alongside '*' โ€” they are explicit entries, so they still work before the first page arrives and a numeric key-value stays searchable. Give any other non-text column an explicit entry or a custom builder.

To offer no search at all, use searchable="false" rather than emptying search-value.

Vue SFC

Turning search off โ€‹

The field is a text box by default, so searchable defaults to true. Pass searchable="false" to make it read-only: it can't be typed into, so it never filters, never queries the server, and no custom tag can be entered that way. Everything else is unchanged โ€” clicking opens the dropdown, arrows and Enter pick, Backspace removes the last chip.

Vue SFC

Grouped options โ€‹

display-group is an array with one accessor per level (string field or function). Add the boolean group to bucket a paginated source client-side, or feed pre-grouped { key, items } data directly; group-sticky pins headers.

Two levels over a 1,200-row static array, load-more="scroll" revealing a chunk at a time.

Vue SFC

Pre-grouped data with custom group-key / group-items field names.

Vue SFC

Width & height โ€‹

Set width, height, min-width, max-width, min-height or max-height โ€” each takes a CSS string ("320px", "80%") or a number (px). Fields are full width by default; set width to constrain.

Vue SFC

Placement โ€‹

The suggestions panel keeps itself inside the viewport, so a field near the bottom of the page is never clipped:

  • flip (default true) opens the suggestions upward when there isn't room below.
  • shift (default true) slides them horizontally so they don't overflow a screen edge.
  • When neither side fits the full list, it opens on the roomier side and shrinks to fit, scrolling internally. This caps dropdownHeight / dropdownMaxHeight โ€” those stay the requested size whenever there is room for them.

Set :flip="false" / :shift="false" to pin the suggestions below the field.

CSS Variables โ€‹

Vue SFC

Themed through --mono-tag-input-* custom properties (they inherit and pierce the shadow boundary); an explicit --mono-tag-input-focus-color override wins over the color prop. Re-skin globally via the --theme-* tokens.

VariableDefaultControls
--mono-tag-input-focus-color--theme-primaryFocus / hover border (set by color)
--mono-tag-input-focus-rgbprimary rgbFocus ring color (as r, g, b)
--mono-tag-input-underline-glow0 5px 6px -6pxUnderlined focus glow geometry
--mono-tag-input-cursor-width3pxKeyboard-cursor bar on the highlighted suggestion
--mono-tag-input-cursor-color--mono-tag-input-focus-colorColour of that bar
--mono-tag-input-text--theme-textField + label text color
--mono-tag-input-border--theme-borderField border color
--mono-tag-input-surface--theme-surfaceDropdown surface
--mono-tag-input-background--theme-backgroundField background base
--mono-tag-input-success--theme-successValid-state color
--mono-tag-input-danger--theme-dangerInvalid / required color
--mono-tag-input-warning--theme-warningWarning-state color

The tag chips are painted by chip's stylesheet, so --mono-tag-input-focus-color recolors them along with the field โ€” unless chip.color pins a hue, which opts them out. For finer control, set the matching --mono-chip-* variable on the field.

Types โ€‹

Importimport { TagInputProps } from 'mono-helper'
PropValueDefaultDescription
modelValueunknown[]โ€”Two-way bound array of selected tag values.
valueunknown[]โ€”Selected tag values (kept in sync with modelValue).
itemsstring | TagInputItem[]โ€”Suggestion items to choose from.
dataSourceTagInputDataSource<TagInputItem>โ€”DataSource driving the suggestions; takes precedence over items.
immediatebooleanโ€”DataSource-only: auto-load the source on attach when it has no items yet.
loadMore'' | 'button' | 'scroll' | booleanโ€”Incremental loading mode; enabling defaults to scroll, button opts into a button.
pageSizenumberโ€”Chunk size used when paging a plain items array (default 10).
dropdownHeightstring | numberโ€”Fixed height of the scrollable suggestions list.
dropdownMaxHeightstring | numberโ€”Max height of the scrollable suggestions list.
stayOpenbooleanโ€”Exempt this tag-input from every automatic close โ€” clicking or focusing anything outside it, which includes opening another one. Not a lock: its own trigger, Escape and picking an item still close it.
keyValuestringโ€”Property name on each item used as the stored tag value.
displayValuestring | (item: TagInputItem) => stringโ€”Property name or selector function deriving each item's display text.
displayGroupTagInputDisplayGroupโ€”Per-level accessors for grouped options (header label per group level).
groupKeystringโ€”Field holding a group node's key (default 'key').
groupItemsstringโ€”Field holding a group node's child array (default 'items').
groupbooleanโ€”Group a plain, paginated DataSource (or flat array) client-side.
groupStickybooleanโ€”Keep group headers pinned to the top while their rows scroll.
searchablebooleanโ€”Whether typing in the field searches (default `true`; `false` = read-only input).
searchValuestring | MonoSearchExprEntry[]โ€”Field(s) the search matches (server query + client filter target). A comma string or an array; entries may be plain columns, paths (`Company.Name`, `Transaction.[*].Price`), `*` patterns (`'*'`, `'*.[*].*'`) or, in array form, `{ field, custom }` clause builders.
searchOperationstringโ€”devextreme search operation for server search (default 'contains').
searchDebouncenumberโ€”Debounce (ms) before a server search fires (default 300).
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'โ€”Size of the tag input.
color'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'โ€”Color theme of the tag input.
variant'underlined' | 'outlined' | 'filled'โ€”Visual style of the tag input.
chipstring | TagInputChipPropsโ€”Tag chip configuration โ€” the `mono-chip` props to apply to every tag. Bind it as a real property (`:chip.prop="{ size: 'md' }"`); a plain `chip='{"size":"md"}'` JSON attribute also works for static HTML.
labelstringโ€”Text label shown above the field.
placeholderstringโ€”Placeholder text shown when the input is empty.
helperTextstringโ€”Helper text shown below the field.
validationState'warning' | 'default' | 'valid' | 'invalid'โ€”Validation state controlling field styling.
validationMessagestringโ€”Message shown for the current validation state.
errorMessagestringโ€”Error message that forces the invalid state.
successMessagestringโ€”Success message that forces the valid state.
namestringโ€”Form field name for the underlying input.
disabledbooleanโ€”Disables interaction with the tag input.
readonlybooleanโ€”Makes the tag input read-only.
requiredbooleanโ€”Marks the field as required.
clearablebooleanโ€”Shows a clear button to remove all tags.
allowCustombooleanโ€”Allows adding custom tags not present in the items.
duplicatebooleanโ€”Allows duplicate tag values.
maxTagsnumberโ€”Maximum number of tags that can be added.
checkablebooleanโ€”Checkbox multi-select mode (selected rows stay checked, dropdown stays open).
maxnumberโ€”Max chips shown inline; the rest collapse into a clickable "+N more" chip.
ariaLabelTextstringโ€”Accessible label for screen readers.
ariaLabelstringโ€”โ€”
widthstring | numberโ€”Explicit sizing of the field. Each accepts a CSS length string (`"320px"`, `"80%"`) or a number (interpreted as px). Use `width="100%"` for full width. (Distinct from `dropdownHeight`/`dropdownMaxHeight`, which size the popup.)
heightstring | numberโ€”โ€”
minWidthstring | numberโ€”โ€”
maxWidthstring | numberโ€”โ€”
minHeightstring | numberโ€”โ€”
maxHeightstring | numberโ€”โ€”
cssClassTagInputCssClassโ€”Per-part class overrides for styling internal elements.
visiblebooleanโ€”Whether the control is shown. Defaults to `true`.
visibleType'invisible' | 'none'โ€”How it hides when `visible` is `false`. Defaults to `'none'`.