Tagify: Tags Input Plugin With Autocomplete And Validation
| File Size: | 577 KB |
|---|---|
| Views Total: | 91923 |
| Last Update: | |
| Publish Date: | |
| Official Website: | Go to website |
| License: | MIT |
Tagify is a vanilla JavaScript tags input component that turns an input or textarea into an editable tag and token field.
It supports free-form tags, whitelists, blacklists, autocomplete suggestions, single-select mode, mixed text with inline tags, validation, custom templates, and framework wrappers for React, Vue, and Angular.
Note that this library has deprecated jQuery support starting from v4.23.0, so you can now implement Tagify using Vanilla JavaScript.
Features:
- Converts standard input and textarea elements into tag and token input fields.
- Creates tags from typed delimiters, Enter, Tab, blur, and pasted text.
- Uses whitelists and blacklists to control accepted tag values.
- Shows an autocomplete dropdown with fuzzy search, aliases, custom search keys, and selectable items.
- Validates tags with a regular expression, an HTML pattern attribute, or a custom validation function.
- Edits tags by double-click by default, with a single-click option available through
editTags.clicks. - Stores the original input value as a JSON string by default, which helps preserve tags that contain commas.
- Supports
mixmode for inline mentions, hashtags, or tagged text inside a textarea. - Supports
selectmode for single-value tag selection similar to a searchable select control. - Uses custom template functions for tags, wrappers, dropdown items, dropdown headers, and dropdown footers.
- Exposes instance methods, custom events, callbacks, and Promise-based hooks.
- Works from CDN, npm, and wrapper imports for React and Vue projects.
Use Cases
- Blog and CMS editors need tag fields for post topics, categories, labels, and internal content organization.
- Product filter forms work better when shoppers choose brands, colors, sizes, or attributes from a controlled suggestion list.
- Admin dashboards often need repeatable value inputs for permissions, user roles, project labels, or workflow states.
- Email-style recipient fields use tag chips to show selected contacts, validate entries, and remove addresses quickly.
- Search interfaces can accept multiple keywords or filter tokens while keeping each term editable after entry.
- Comment boxes, template editors, and message fields can use mixed mode for mentions, variables, or structured inline tokens.
How to use it
Install And Include The Files
For a browser setup, load the Tagify stylesheet and script from a CDN.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.css"> <script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify"></script>
For a bundler setup, install the npm package and import the JavaScript and CSS files.
npm i @yaireo/tagify
import Tagify from '@yaireo/tagify'; import '@yaireo/tagify/dist/tagify.css';
Add The HTML Markup
Use a normal text input for standard tag fields. Use a textarea when you need mixed text and inline tags.
<label for="post-tags">Post tags</label> <input id="post-tags" name="tags" value="JavaScript,CSS,Forms" placeholder="Type a tag"> <label for="editor-mentions">Message</label> <textarea id="editor-mentions" name="message" placeholder="Type @ to mention a person"></textarea>
Initialize Tagify
The smallest setup only needs the target element and a new Tagify instance.
const input = document.querySelector('#post-tags');
const tagify = new Tagify(input);
Tagify reads the existing input value, creates tags from it, and keeps the original input value in sync for form submission.
Basic Usage Flow
- Load
tagify.cssbefore the component appears on the page. - Load
@yaireo/tagifyor importTagifyin a module build. - Add an input or textarea that will store the final value.
- Create a Tagify instance with
new Tagify(element, settings). - Read
tagify.valuefor an array of tag objects, or read the original input value for the serialized form value.
Advanced Examples
Tags Input With Whitelist Suggestions
This example restricts accepted tags to predefined values and shows suggestions after the first typed character.
<input id="skills" name="skills" placeholder="Add skills">
const skillsInput = document.querySelector('#skills');
const skillsTagify = new Tagify(skillsInput, {
whitelist: ['JavaScript', 'HTML', 'CSS', 'React', 'Vue', 'Node.js'],
enforceWhitelist: true,
dropdown: {
enabled: 1,
maxItems: 8,
closeOnSelect: false,
highlightFirst: true
}
});
AJAX Suggestions
Use the input event to fetch remote suggestions and update tagify.whitelist. Abort the previous request when the user keeps typing.
const userInput = document.querySelector('#post-tags');
const userTagify = new Tagify(userInput, {
whitelist: [],
dropdown: {
enabled: 2,
maxItems: 10
}
});
let tagController;
userTagify.on('input', event => {
const value = event.detail.value;
tagController?.abort();
tagController = new AbortController();
userTagify.loading(true);
fetch('/api/tags?q=' + encodeURIComponent(value), {
signal: tagController.signal
})
.then(response => response.json())
.then(tags => {
userTagify.whitelist = tags;
userTagify.loading(false);
userTagify.dropdown.show(value);
})
.catch(() => {
userTagify.loading(false);
});
});
Validate Tags And Limit Tag Count
This example accepts lowercase slugs only and limits the field to five tags.
const slugInput = document.querySelector('#post-tags');
const slugTagify = new Tagify(slugInput, {
pattern: /^[a-z0-9-]{2,30}$/,
maxTags: 5,
texts: {
duplicate: 'This tag already exists',
pattern: 'Use lowercase letters, numbers, and hyphens'
},
keepInvalidTags: true
});
Mixed Mode For Mentions And Hashtags
Mixed mode turns selected patterns inside a textarea into inline tags.
<textarea id="comment-box" name="comment"></textarea>
const commentBox = document.querySelector('#comment-box');
const mentionTagify = new Tagify(commentBox, {
mode: 'mix',
pattern: /@|#/,
whitelist: [
{ value: 'alice', type: 'user' },
{ value: 'frontend', type: 'topic' },
{ value: 'javascript', type: 'topic' }
],
dropdown: {
enabled: 1,
position: 'text',
mapValueTo: 'value'
}
});
Sort Tags With DragSort
Tagify needs a drag-and-drop helper for manual tag sorting. After sorting, call updateValueByDOMTags() so the internal value matches the DOM order.
const sortableInput = document.querySelector('#skills');
const sortableTagify = new Tagify(sortableInput);
const dragsort = new DragSort(sortableTagify.DOM.scope, {
selector: '.' + sortableTagify.settings.classNames.tag,
callbacks: {
dragEnd: () => sortableTagify.updateValueByDOMTags()
}
});
Tagify Settings
Core Settings
id: Identifies the instance for persisted whitelist and value data. Type: String. Default: Not specified.tagTextProp: Selects the tag data property shown as the visible tag text. Keepvalueunique in tag objects. Type: String. Default:'value'.placeholder: Sets placeholder text for the component. An HTML placeholder attribute overrides this setting. Type: String. Default: Empty.delimiters: Splits typed text into tags by a regular expression string. Type: String. Default:','.pattern: Validates tag input with a regular expression string or RegExp. The HTMLpatternattribute can set this too. Type: String or RegExp. Default:null.mode: Changes the component mode. Useselectfor single-value selection ormixfor inline tags inside text. Type: String. Default:null.mixTagsInterpolator: Sets the opening and closing markers for mixed tags. Type: Array. Default:['[[', ']]'].mixTagsAllowedAfter: Defines the characters that may appear after a mixed tag. Type: RegExp. Default:/,|\.|:|\s/.maxTags: Sets the maximum number of accepted tags. Type: Number. Default:Infinity.originalInputValueFormat: Replaces the default JSON string format stored in the original input. Return a string from this function. Type: Function. Default: Not specified.
Tag Creation And Validation Settings
duplicates: Controls duplicate tag values. Type: Boolean. Default:false.trim: Removes leading and trailing spaces from tag values. Type: Boolean. Default:true.enforceWhitelist: Accepts only values that exist in the whitelist. In mix mode,falseblocks creation of new tags. Type: Boolean. Default:false.userInput: Controls manual typing, pasting, and editing. The original inputdisabledattribute can also set this behavior. Type: Boolean. Default:true.addTagOnBlur: Converts typed text into a tag when the field loses focus. Type: Boolean. Default:true.addTagOn: Sets the user actions that convert loose text into a tag. Type: Array. Default:['blur', 'tab', 'enter'].onChangeAfterBlur: Keeps native input change behavior so the change event fires after blur. Type: Boolean. Default:true.pasteAsTags: Converts pasted text into one or more tags. Type: Boolean. Default:true.callbacks: Maps Tagify event names to callback functions during initialization. Type: Object. Default:{}.validate: Validates a tag data object. Returntrue,false, or an error message string. Type: Function. Default: Not specified.transformTag: Mutates tag data before tag creation, editing, and validation. Type: Function. Default: Not specified.keepInvalidTags: Keeps invalid tags visible so users can see the error reason. Type: Boolean. Default:false.createInvalidTags: Creates invalid tags. When set to false, Tagify keeps text in the editable input. Type: Boolean. Default:true.skipInvalid: Skips invalid temporary tags. Type: Boolean. Default:false.blacklist: Lists tag values that users cannot add. Type: Array. Default:[].whitelist: Lists accepted or suggested tags. String, number, and object items are supported. Object items need a uniquevalueproperty. Type: Array. Default:[].
Editing, Focus, And Keyboard Settings
editTags: Controls tag editing behavior. Usefalseornullto block editing. Type: Object or Number. Default:{}.editTags.clicks: Sets the click count required to start edit mode. Type: Number. Default:2.editTags.keepInvalid: Keeps invalid edits until the user presses Escape. Type: Boolean. Default:true.focusable: Lets the component wrapper receive focus. Type: Boolean. Default:true.focusInputOnRemove: Refocuses the input after a tag is removed. Type: Boolean. Default:true.backspace: Controls Backspace behavior when the internal input is empty. Usetrueto remove the previous tag,'edit'to edit it, orfalseto do nothing. Type: Mixed. Default:true.allowCaretBetweenTags: Lets left and right arrow keys move the internal input between tags in non-mix modes. Type: Boolean. Default:true.
Autocomplete Settings
autoComplete.enabled: Suggests the rest of a matching whitelist value while the user types. Type: Boolean. Default:true.autoComplete.rightKey: Uses the right arrow key to accept an autocomplete value. Type: Boolean. Default:false.autoComplete.tabKey: Uses the Tab key for autocomplete selection before tag creation. Type: Boolean. Default:false.
Dropdown Settings
dropdown.enabled: Sets the minimum number of typed characters required before the suggestions dropdown appears. Usefalseto disable it. Type: Number or Boolean. Default:2.dropdown.maxItems: Limits the number of rendered suggestion items. Type: Number. Default:10.dropdown.classname: Adds a custom class to the suggestions dropdown. Type: String. Default: Empty string.dropdown.fuzzySearch: Matches typed text inside whitelist item values and at the beginning of values. Type: Boolean. Default:true.dropdown.caseSensitive: Requires exact case matching for selected suggestions and duplicate checks. Use it withdropdown.fuzzySearch: false. Type: Boolean. Default:false.dropdown.accentedSearch: Matches accented whitelist items when the typed text omits the accent. Type: Boolean. Default:true.dropdown.sortby: Sorts filtered suggestions. Use'startsWith'or a custom function. Type: String or Function. Default: Whitelist order.dropdown.includeSelectedTags: Keeps already selected tags in the suggestion list and marks them as selected. Type: Boolean. Default:false.dropdown.escapeHTML: Escapes HTML entities in rendered suggestion text. Type: Boolean. Default:true.dropdown.position: Controls dropdown placement. Use'all','text','input', or'manual'. Type: String. Default:'all'.dropdown.RTL: Aligns the dropdown for right-to-left layouts. Type: Boolean. Default:false.dropdown.highlightFirst: Highlights the first suggestion and offers it as an autocomplete value. Type: Boolean. Default:false.dropdown.closeOnSelect: Closes the dropdown after a suggestion is selected. Type: Boolean. Default:true.dropdown.clearOnSelect: Clears typed text after a suggestion is selected. Type: Boolean. Default:true.dropdown.mapValueTo: Selects the whitelist object key or function result shown in the dropdown. Type: Function or String. Default: Not specified.dropdown.searchKeys: Searches additional whitelist object keys during suggestion filtering. Type: Array. Default:['value', 'searchBy'].dropdown.appendTarget: Sets the DOM node that receives the rendered dropdown. A function may return the target node. Type: HTMLNode or Function. Default:document.body.dropdown.placeAbove: Forces the dropdown above or below the input when set. Type: Boolean. Default: Not specified.
Template, Mix Mode, And Accessibility Settings
templates: Replaces Tagify template functions. Supported templates includewrapper,input,tag,dropdown,dropdownItem,dropdownContent,dropdownHeader,dropdownFooter, anddropdownItemNoMatch. Type: Object. Default: Built-in templates.mixMode.insertAfterTag: Adds a node or string after a tag in mixed mode. Type: Node or String. Default:\u00A0.a11y.focusableTags: Lets tags receive focus and receive Backspace deletion. Type: Boolean. Default:false.a11y.inputAriaLabel: Sets an accessible name on Tagify's internal editable input. Type: String. Default:'Tags input field'.
Methods
tagify.destroy(): Restores the original input element and removes the Tagify UI. Parameters: None. Returns: Not specified.tagify.removeAllTags(): Removes all tags and resets the original input value. Parameters: None. Returns: Not specified.tagify.addTags(tags, clearInputAfterAdding, skipAddingInvalids): Adds one or more tags from a string, object, string array, or object array. Parameters: Tags, Boolean, Boolean. Returns: Not specified.tagify.addMixTags(tags): Adds mixed-mode tags at the saved caret location or at the end. Parameters: Array or String. Returns: Not specified.tagify.addEmptyTag(tagData): Creates an empty tag and immediately starts edit mode. Parameters: Object. Returns: Not specified.tagify.removeTags(tags, silent, tranDuration): Removes one or more tags. If no tag is passed, it removes the last tag. Parameters: Array, HTMLElement, or String; Boolean; Number. Returns: Not specified.tagify.loadOriginalValues(value): Converts the original input value into tags. Tagify runs this during initialization. Parameters: String or Array. Returns: Not specified.tagify.getTagIndexByValue(value): Returns the index of a tag by value. Parameters: String. Returns: Number.tagify.getTagElmByValue(value): Returns the first matching tag element. Parameters: String. Returns: HTMLElement or not found.tagify.isTagDuplicate(value): Returns the duplicate count for a value. Parameters: String. Returns: Number.tagify.parseMixTags(value): Converts a mixed-tag string into HTML with tags and text. Parameters: String. Returns: Not specified.tagify.getTagElms(): Returns all tag DOM nodes. Parameters: None. Returns: NodeList.tagify.getTagElmBeforeInput(): Returns the tag element immediately before the internal input. Parameters: None. Returns: HTMLElement orundefined.tagify.repositionScopeInput(direction, options): Moves the internal input among tag siblings or after the last tag. Parameters: Direction string and optional options object. Returns: Boolean.tagify.getSetTagData(tagElm, tagData): Reads or updates data stored on a tag element. Parameters: HTMLElement, Object. Returns: Not specified.tagify.editTag(tagElm): Starts edit mode on a tag element. Parameters: HTMLElement. Returns: Not specified.tagify.getTagTextNode(tagElm): Returns the node that contains the visible tag text. Parameters: HTMLElement. Returns: Node.tagify.setTagTextNode(tagElm, text): Updates visible tag text in the DOM only. Parameters: HTMLElement, String. Returns: Not specified.tagify.replaceTag(tagElm, tagData): Exits edit mode and replaces the tag element with updated data. Parameters: HTMLElement, Object. Returns: Not specified.tagify.loading(state): Toggles the loading state for the whole component. Parameters: Boolean. Returns: Not specified.tagify.tagLoading(tagElm, state): Toggles the loading state for a specific tag. Parameters: HTMLElement, Boolean. Returns: Not specified.tagify.createTagElem(tagData): Creates a tag element from tag data. Parameters: Object. Returns: HTMLElement.tagify.injectAtCaret(node, range): Inserts a text or HTML node at the saved caret position. Parameters: HTMLElement and optional range object. Returns: Not specified.tagify.placeCaretAfterNode(node): Places the caret after a node. Parameters: HTMLElement. Returns: Not specified.tagify.setRangeAtStartEnd(start, node): Places the caret at the start or end of a node. Parameters: Boolean, HTMLElement. Returns: Not specified.tagify.insertAfterTag(tagElm, nodeOrString): Inserts a node or string after a tag. Parameters: HTMLElement, HTMLElement or String. Returns: Not specified.tagify.toggleClass(state): Toggles a class on the main Tagify container. Parameters: Boolean. Returns: Not specified.tagify.dropdown.selectAll(): Adds all whitelist items as tags and closes the dropdown. Parameters: None. Returns: Not specified.tagify.dropdown.show(value): Opens the suggestions dropdown and filters it by a string when provided. Parameters: String. Returns: Not specified.tagify.dropdown.hide(force): Hides the suggestions dropdown. Parameters: Boolean. Returns: Not specified.tagify.dropdown.toggle(force): Toggles the suggestions dropdown. A Boolean parameter can force the state. Parameters: Boolean. Returns: Not specified.tagify.updateValueByDOMTags(): Rebuildstagify.valuefrom the current tag DOM order. Use it after drag sorting. Parameters: None. Returns: Not specified.tagify.parseTemplate(template, data): Converts a named or supplied template function into a DOM node. Parameters: String or Function, Array. Returns: DOM node.tagify.setReadonly(state): Toggles readonly mode. Parameters: Boolean. Returns: Not specified.tagify.setDisabled(state): Toggles disabled mode. Parameters: Boolean. Returns: Not specified.tagify.getPersistedData(key): Reads persisted data for the instance. Parameters: String. Returns: Not specified.tagify.setPersistedData(value, key): Saves persisted data under the Tagify namespace. Parameters: Any value, String. Returns: Not specified.tagify.clearPersistedData(key): Clears persisted data for a key or for the instance when no key is passed. Parameters: String. Returns: Not specified.tagify.setPlaceholder(value): Updates the placeholder text. Parameters: String. Returns: Not specified.
Events, Callbacks, And Hooks
Listen To Events
Tagify events use .on(eventName, callback) and .off(eventName, callback). Event-specific data appears in event.detail.
const input = document.querySelector('#post-tags');
const tagify = new Tagify(input);
function onTagInput(event) {
console.log(event.detail.value);
}
tagify
.on('input', onTagInput)
.on('add', event => console.log(event.detail.data))
.on('remove', event => console.log(event.detail.data));
// Remove a listener later.
tagify.off('input', onTagInput);
Event Reference
change: Runs after the value changes. Arguments:event.detail.valueas a string. Trigger: Value change.add: Runs after a tag is added. Arguments: Event detail object. Trigger: Tag creation.remove: Runs after a tag is removed. Legacy jQuery usage should avoid the jQueryremoveconflict and use the Tagify instance directly. Arguments: Event detail object. Trigger: Tag removal.invalid: Runs when a tag fails validation. Arguments: Event detail object. Trigger: Invalid tag creation.input: Runs while a tag is typed or edited. Arguments:value,inputElm, andisValidinevent.detail. Trigger: Input change.paste: Runs after text is pasted into the component. Arguments: Event detail object. Trigger: Paste action outside tag edit mode.click: Runs when a tag is clicked. Arguments: Tag element, index, and data. Trigger: Tag click.dblclick: Runs when a tag is double-clicked. Arguments: Event detail object. Trigger: Tag double-click.keydown: Runs when the internal input has focus and the user presses a key. Arguments: Keyboard event details. Trigger: Keydown.focus: Runs when the component gains focus. Arguments: Event detail object. Trigger: Focus.blur: Runs when the component loses focus. Arguments: Event detail object. Trigger: Blur.edit:input: Runs while the user types inside an edited tag. Arguments: Event detail object. Trigger: Edited tag input.edit:beforeUpdate: Runs before Tagify updates an edited tag. Arguments: Event detail object. Trigger: Edit update pending.edit:updated: Runs after a tag changes through edit mode orreplaceTag(). Arguments: Event detail object. Trigger: Edit update complete.edit:start: Runs when a tag enters edit mode. Arguments: Event detail object. Trigger: Edit mode start.edit:keydown: Runs on keydown while an edited tag has focus. Arguments: Keyboard event details. Trigger: Edited tag keydown.dropdown:show: Runs when the suggestions dropdown is about to render. Arguments: Dropdown DOM node. Trigger: Dropdown show.dropdown:hide: Runs after the suggestions dropdown leaves the DOM. Arguments: Event detail object. Trigger: Dropdown hide.dropdown:select: Runs when the user selects a suggestion by mouse, keyboard, or touch. Arguments: Event detail object. Trigger: Suggestion selection.dropdown:scroll: Runs while the dropdown scrolls and reportsevent.detail.percentage. Arguments: Scroll percentage. Trigger: Dropdown scroll.dropdown:noMatch: Runs when no whitelist item matches the typed input. Arguments: Event detail object. Trigger: Empty suggestion result.dropdown:updated: Runs when the visible suggestions list is re-filtered after tag changes. Arguments: Event detail object. Trigger: Dropdown refresh.
Callbacks Object
Events can also be registered during initialization through the callbacks setting.
const input = document.querySelector('#post-tags');
const tagify = new Tagify(input, {
callbacks: {
change: event => console.log(event.detail.value),
'dropdown:show': event => console.log(event.detail)
}
});
Promise-Based Hooks
beforeRemoveTag: Runs before Tagify removes one or more tags. Resolve the Promise to continue or reject it to cancel. Arguments: Array of tag objects. Trigger: Tag removal request.suggestionClick: Runs during suggestion click handling. Arguments: Click event data object. Trigger: Suggestion click.beforePaste: Runs before pasted text enters Tagify. Resolve with a changed paste value when needed. Arguments: Tagify instance, pasted text, clipboard data. Trigger: Paste action.beforeKeyDown: Runs on browser keydown after the Tagifykeydownevent. Arguments: Not specified. Trigger: Keydown.
const input = document.querySelector('#post-tags');
const tagify = new Tagify(input, {
hooks: {
beforeRemoveTag(tags) {
return new Promise((resolve, reject) => {
const tagName = tags[0].data.value;
window.confirm('Remove ' + tagName + '?') ? resolve() : reject();
});
}
}
});
HTML Attributes
pattern: Sets the tag validation pattern from the original input. Example:<input pattern="^[A-Za-z0-9-]{2,30}$">.placeholder: Sets placeholder text from the original input. Example:<input placeholder="Type a tag">.readOnly: Blocks add, remove, and edit interactions. Example:<input readOnly>.autofocus: Focuses the Tagify component after load. Example:<input autofocus>.required: Adds a required attribute to the Tagify wrapper. Example:<input required>.
Output Value And Form Submission
Tagify keeps two values available: tagify.value as an array of tag objects and the original input value as a JSON string. The JSON string format is safer for tags that contain commas, addresses, or extra properties.
const input = document.querySelector('#post-tags');
const tagify = new Tagify(input);
tagify.on('change', event => {
console.log(tagify.value); // Array of tag objects
console.log(event.detail.value); // JSON string stored in the input
});
Use originalInputValueFormat only when your backend expects a different string format.
const input = document.querySelector('#post-tags');
new Tagify(input, {
originalInputValueFormat: values => values.map(item => item.value).join(',')
});
Dependency And Version Notes
- Current Tagify usage targets vanilla JavaScript first and does not require jQuery.
- The package includes React and Vue import paths. React usage imports
@yaireo/tagify/react, and Vue usage imports@yaireo/tagify/vue. - The jQuery wrapper is deprecated. Older packages included
jQuery.tagify.jsfor selector chaining and simple event binding. - Legacy jQuery code can still access the Tagify instance through
$('[name=tags]').data('tagify')when that old wrapper is available. - Current package metadata excludes IE 11. Treat IE polyfill snippets from older examples as legacy-only code.
- Building Tagify from source uses newer Node and pnpm requirements. Normal npm installation only needs
npm i @yaireo/tagify.
Alternatives And Related Resources
- 10 Best Tags Input Plugins In jQuery & Vanilla JavaScript: Compare Tagify with other tag input plugins and plain JavaScript alternatives.
- selectize.js: Use this jQuery option when you need tagging and custom select behavior in the same form control.
- Tagsinput.js: Use this Bootstrap-focused jQuery tag input when the project still depends on Bootstrap tag styling.
- Choices.js: Use this vanilla JavaScript select and input enhancer for select boxes, multi-selects, and text inputs.
- Emblor: Use this shadcn/ui tag input component in React and Next.js interfaces.
FAQs
Q: Does Tagify require jQuery?
A: Current Tagify usage does not require jQuery. The old jQuery wrapper is deprecated and mainly serves legacy pages that already loaded older Tagify packages.
Q: Why do my Tagify styles look broken?
A: The stylesheet is required. Load @yaireo/tagify/dist/tagify.css before the component renders, or import it in your bundler entry file.
Q: How should tag values be sent to a backend?
A: The original input value stores a JSON string by default. Keep that format when tags may contain commas or extra fields such as IDs, classes, or read-only state.
Q: How do I update remote suggestions after initialization?
A: Assign the new array to tagify.whitelist, not tagify.settings.whitelist. Then call tagify.dropdown.show(value) when you want to show the refreshed suggestions.
Q: Can Tagify create inline mentions inside text?
A: Use mode: 'mix' with a pattern such as /@|#/. A textarea is the usual target for mixed text and inline tags.
Changelog:
v4.38.0 (2026-06-28)
- bugfixes
v4.37.1 (2026-04-20)
- bugfixes
v4.37.0 (2026-04-04)
- bugfixes
- improvements
v4.36.0 (2026-01-19)
- bugfixes
- improvements
v4.35.6 (2025-11-17)
- bugfixes
- refactor injectAtCaret and appendMixTags methods
v4.35.5 (2025-11-03)
- bugfixes
v4.35.4 (2025-08-29)
- bugfixes
v4.35.3 (2025-07-22)
- bugfixes
v4.35.2 (2025-07-13)
- refactor: update update method to accept a callback and added a call to tgigger the 'remove' event when removeAllTags is called
- moved UPDATE_DELAY to the constants file and trigger 'remove' event in removeAllTags
- bugfixes
v4.35.1 (2025-05-10)
- Fix "TypeError: Cannot destructure property 'added' of 'compareStrings(...)' as it is undefined."
v4.35.0 (2025-04-24)
- Refactor and bugfix
v4.34.0 (2025-04-10)
- Bugfixes
v4.33.2 (2025-01-27)
- Bugfixes
v4.33.1 (2025-01-11)
- Bugfixes
v4.33.0 (2024-12-22)
- Bugfixes
- slightly increased $tag-inset-shadow-size CSS variable
v4.32.2 (2024-12-08)
- Enhance keyboard navigation for suggestions dropdown by adding support for PageUp, PageDown, Home, and End keys. This allows users to navigate through suggestions more efficiently without using the mouse.
- bugfix: in select-mode, the x (remove tag) button should not be visible if the suggestions' dropdown is visible (open)
- ran npx update-browserslist-db@latest 0ea0f30
- bugfix: Dropdowns does not close when interacting with tags of other instances
- added an FAQ item
- this.state.dropdown.suggestions should point to the sorted list and not pre-sorted one
- call the custom sortby (if defined) also when there's no search query
- Fix scroll behavior
v4.32.1 (2024-11-23)
- in normal mode, if there is a single tag and while the dropdown is open the tag's x button is clicked, then the component should be re-focused
- removed e.preventDefault for tab keydown event
v4.32.0 (2024-11-12)
- bugfixes
v4.31.6 (2024-10-29)
- bugfixes
- should tab-autocomplete a tag from the whitelist and with all its data, instead of only the suggetion's text, which is incorrect in case of a whitelist collection
v4.31.4/5 (2024-10-25)
- bugfixes
v4.31.3 (2024-08-31)
- bugfixes
v4.31.2 (2024-08-29)
- add event should fire ASAP without any delay. Also should include invalid added tags
v4.31.1 (2024-08-26)
- Bugfixed
v4.31.0 (2024-08-24)
- Updated
v4.27.0 (2024-06-23)
- added a div wrapper to prevent bug
- bugfix - clicking the × (clear selected tag) button in select-mode, the component should not get focused
- added tagify-dd-text-color to Knobs in the examples html page
- minor refactor
- added class name this.settings.classNames.dropdownItemSelected (tagify__dropdown__item--selected) for selected dropdown items
- added new CSS variable --tagify-dd-text-color
- added CSS for suggestion items which are currently already selected (as tags)
v4.26.6 (2024-06-12)
- chore: added a updatePlaceholderByTagsCount funciton to the advance-options demo to showcase the tagify.setPlaceholder method
- chore: added 2 methods to the table of available tagify methods in the README: setRangeAtStartEnd & setPlaceholder
- bugfixes
v4.26.5 (2024-05-14)
- bugfixes
- small CSS change regarding tags' appeared line-height
v4.26.4 (2024-05-11)
- bugfixes
v4.26.3 (2024-05-09)
- clicking anywhere within an instance's dropdown should not hide it
- add a custom property to the dropdown node so it be linked to which tagify instance it belongs to
- bugfixes
v4.26.2 (2024-05-07)
- should discard tags added as objects with an empty text-prop value
- refactored the "bindOriginaInputListener" interval so it will be restarted every time Tagify gets updated so the comparison of the original value will only happen after Tagify was updated for certain
- When the trim setting is true, tags added as objects should be trimmed as well
- normalizeTags() method should eliminate empty array items
- bugfixes
v4.26.1 (2024-05-02)
- Bugfixes
v4.26.0 (2024-04-29)
- Bugfixes
v4.25.1 (2024-04-25)
- Refactored wrapper HTML template by extracting the input into its own template function
v4.25.0 (2024-04-25)
- Refactored wrapper HTML template by extracting the input into its own template function
- Added keyboard ENTER support for deleting selected tag using TAB navigation when in select-mode
- Fixed bugs
2024-04-15
- Updated doc
- Updated demos
v4.23.0 (2024-04-09)
- Minor CSS change to tag's max width
- Added a new setting - focusable
- Simplified the condition because dropdown.enabled is changed to 0 automatically if userInput is set to false by the applySettings method
- cursor: text CSS property should only be applied if Tagify has an editable node within
- Added a this.removeAllCustomListeners as a cleanup stage inside the destroy method
- Added ability to remove all the events listeners for a specific type of an event, without specifying the callbacks as they are saves internally - Added ability to remove all the events assigned on the instance
- Bugfixes
v4.22.2 (2024-03-19)
- bugfixes
v4.22.0 (2024-03-17)
- minor code adjustment for select mode
- changed the focus and blur events for the input element to global focusin & focusout events because they can be propagated, and more flexible to work with because it doesn't resrict working only with the input element
- dropdown.show() method should do nothing if this.state.dropdown.visible is true
- select mode should not auto-complete when pressing the TAB button because the autocomplete method cannot currently work for select mode since it only works for the input element which is hidden in select mode 10078f1
- added new helper method isWithinNodeTag to test if a certain node is nested inside a tag element
- fixed bugs
v4.21.2 (2024-03-08)
- bugfixes
v4.21.1 (2024-02-13)
- dropdownItemNoMatch content should not have empty spaces as it will show up in the HTML when injected.
- refactored logic for post-processing a tag node which was just added to the DOM.
v4.21.0 (2024-02-13)
- prepareNewTagNode method should return the modified tagData which includes the __isValid property
- [refactor] moved suggestions-related methods outside of dropdown.js into a new file: suggestions.js for seperation between the dropdown which is just a container and the actual suggestions and their logic code
- fixed banner issues
- added a README section for the bundle's output files
- refactored similar user-input-to-tag preparation logic into a new method prepareNewTagNode which is called by addTags, addMixedTags & prefixedTextToTag
- decided it's better to have the dropdown.highlightFirst setting set to true by default
- selectOption dropdown method should not return on mix-mode when this.DOM.input.parentNode does not exists
- [Chore] Added javascript sourcemaps support which required replacing rollup-plugin-banner with rollup-plugin-banner2 which does supports sourcemaps. Also fixed the banner comment which seems to have not been correct for a long time
v4.20.0 (2024-02-11)
- Fixed numbers-only whilelist not showing with userInput:false setting
- Added paste event listener
- The global onClickAnywhere event should be of type capture to guarantee it will fire before any other event so not to mess state.hasFocus)
- Fixes - Tagify within a label element can't get focused as the focus it shifted to the hidden original field
- select-mode can only have one tag, so replaced block margin (up/down) with padding so the tag will occuy the whole space of the container and have a larger clicking area
- Prevented dblclick event from being listened to in select mode, since there is no need for it.
- In `select mode, clicking on the icon which toggles the dropdown should toggle it when it is already open. refactored that part.
- Remove console.log call
v4.19.1 (2024-01-30)
- bugfixes
v4.19.0 (2024-01-28)
- improved the users list demo in the main demos page
- moved last commented change this.state.hasFocus to a better location in the code
- improved README with a better "basic example" section
- re-made how "select" mode works so instead of the input being editable, the actual tag is now visible and goes into edit-mode and the input is hidden
- removed a console.log
- when calling addEmptyTag method, the Tagify field should be focused
- in case the suggestions DropDown is placed inside the tagify.DOM.scope node, it should not inherit its line-height style
- dropdown.appendTarget setting can now be a function as well, which should return a DOM node
- fix - calling addEmptyTag() with dropdown.enabled: 0 setting should create an empty tag with a dropdown of suggestions
v4.18.3 (2024-01-18)
- Bugfixed
- Don't hide dropdown during whitelist fetch
- re-expose placeCaretAfterNode which was left out after past refactoing. devs should have access to this method
- Stop logging input keystrokes
v4.18.2 (2024-01-12)
- Bugfixed
v4.18.1 (2024-01-08)
- Bugfixed
v4.18.0 (2024-01-05)
- Added escapeHTML dropdown setting which optionally allows HTML to be rendered inside the value of each suggestion item
- The positioning code now takes into considerations the RTL dropdown setting which rendered the suggestions dropdown as if it sticks to the right side of the Tagify.
- Added conditional class name tagify__dropdown--RTL to the dropdown wrapper
- added cx helper function for working with complex class names
- Added --tagify-dd-item-pad global CSS description
- Replaced margins at several places with logical margins, for RTL support
- Added --tagify-dd-max-height as global variable for an easier control over it - Added RTL support for the suggestions dropdown, but it only makes sense if the max-width of the dropdown is set to none or any other value greater than the Tagify width
- Re-instated minification for the jQuery-wrapper output file
- Random minor CSS refactor
v4.17.9 (2023-08-20)
- lots of bugs fixed
v4.17.8 (2023-04-13)
- lots of bugs fixed
v4.17.7 (2023-01-17)
- lots of bugs fixed
v4.17.5 (2022-12-04)
- changes React file from js to jsx
- mix-mode is better initialized by default with dropdown.position as text
- bugfixes
v4.17.4 (2022-11-20)
- Bugfix
v4.17.3 (2022-11-18)
- Bugfix
v4.17.2 (2022-11-16)
- Bugfix
v4.17.1 (2022-11-16)
- removed exports from package.json as it seemed to have caused problems with importing the package due to misconfiguration. Will work on that more.
- moved tagData from the prototype to the "helpers" file, and renamed it getSetTagData
v4.17.0 (2022-11-13)
- Bugfixed
v4.16.4 (2022-09-04)
- Bugfixed
v4.16.3 (2022-09-01)
- Bugfixed
v4.16.2 (2022-08-20)
- Bugfixed
v4.16.0 (2022-08-15)
- Bugfixed
v4.15.4 (2022-08-14)
- Bugfixed
- Renamed originalEvent to event in multiple events - removed cloneEvent in EventDispatcher.js since it was already defined apparently in tagify.js
v4.15.3 (2022-08-06)
- Fixed bugs
v4.15.2 (2022-07-31)
- Fixed bugs
v4.15.1 (2022-07-31)
- Fixed bugs
v4.15.0 (2022-07-30)
- added support for sending the original event to the "trigger" events method
- added support for transitioning-out the selected suggestion item
- when removing all tags, the dropdown should re-filter, because that action might have been triggered from inside the dropdown, and it might still be open
- added dropdown variables to knobs in the examples page
- refactored users-list CSS example to use --tagify-dd-item-pad variable instead of hard-coded property setter
- minor improvements to the horizontal tags hidden transition
- attach a custom property __tagify`` reference to the Tagify instance on the original input and is now returning that instance if the same original input is re-tagified (for some reason)
- chore - added README info for some new CSS variables + ones which were not mentioned before regarding the suggestions dropdown
- fixes - underlying Tagify shoud not get focused when selecting a suggestion from a Tagify sugegstion dropdown which is rendered over it.
- fixes - do not create tags from invalid input. Added the new createInvalidTags setting
- fixes - add an easy was to set tags border-radius using CSS variables
v4.14.1 (2022-07-26)
- Fixed bugs
v4.14.0 (2022-07-21)
- improved the explenation for the Tags with properties section in the examples page
- fixed bugs
v4.13.3 (2022-07-14)
- Bugfixes
v4.13.2 (2022-07-12)
- Fixed wrong duplicate tag with capital letter
v4.13.1 (2022-07-10)
- added the this instance scope as the second parameter to the tag template react
v4.13.0 (2022-07-10)
- Filter only the dropdown-item elements (not header/footer/custom ones) when moving with up/down arrows
- Refactored and fixed the escape scenario when editing tags, so the original tag is now being replaced back correctly
- Changed "__originalHTML" to point to a cloned element instead of innerHTML, so when pressing escape, it will be replaced back to that, as-is
- Fixes - Selected tag disappears after the input loses focus when in select mode.
- Update templates.js
- Update tagify.test.js
- Improved users-list demo
- Added function comment
- Added some new methods
- Refactored editTag method and added 3 new methods: editTagChangeDetected, getTagTextNode & setTagTextNode
- Fixes - add missing css color variable to the suggested text
- Mentioned more templates recently added
- Fixes - Tag doesn't get added on selecting value from custom template dropdownItemNoMatch
- Fixed typo
- Fixed some typos and added async validation example
- Fixes - clicking an uneditable tag when the editTags settings is set to clicks: 1 gives focus to the Tagify field which cannot be unfocused by clicking outside
- Removed data-editable attribute for tags done in previous commit. better its added by the developer and not automatically by Tagify
- Refactored. removed all CSS variables fallbacks to SCSS variables because they already have fallbacks...
- Added "data-editable" for tags (default is undefined which means "true")
- Removed unneeded left-trim because the the returned value is already trimmed
- Updated eslintrc file
- Removed unused package gulp-eslint
- Updated eslintrc file
- Fixes - support originalInputValueFormat setting in mix-mode
- Fixed some mix-mode issues with new line before/after tags in FF/Chrome. Still a bug for new line before a tag in FF causes double BRs
- Fixed placeCaretAfterNode after last change in the function
- Fixes - Editing a tag, allows you to have duplicated tags (case insenstitve)
- Removed the fix done for #653 as it seems fixed in Chrome
- Fixes - injecting a tag node using injectAtCaret without prior focus results in an error
- Fix Changed order of if clauses in iterateChildren function
- Fixing typo
v4.12.0 (2022-04-26)
- editing existing valid tag by adding spaces before or after, should not affect validation, unless the trim setting is false
- fixed - transformTag setting can make a tag invalid when editing
- exposed the helpers for outside usage
- added a comment 381ee1d
- fixed - dropdownFooter shows "Refine your search" when maxItems = 0 (which shows all items)
v4.11.0 (2022-04-11)
- improved the example for the users-list. it now uses the new dropdown header template instead of the hacky way it used to work
- stop adding a tag when blured in select-mode - when typing a tag and blurring, if the typed text is not included in the whitelist, it will be cleared
- do not render the dropdown header template if there's nothing in it
- added 2 new templates for dropdown header & footer
- fixes - keyboard shortcut for bold and italic interfere with mix-mode output
- for "select" mode - if text value is not in the whitelist, clear it once the input is blured
- fixes - Tagify can change a tag value to its tagTextProp under mysterious circumstances
- fixes - destroy() method throws DOM not defined exception
v4.10.0 (2022-04-06)
- now same styles as applied for "readonly" will also apply to "disabled", mainly so the X button will not be rendered
- bugfixes
v4.9.8 (2022-02-18)
- removed unneeded line after recent change which moved this to another onEditDone
- fixed lots of bugs
v4.9.7 (2022-02-14)
- fixed: "strim" setting has no affect on "loadOriginalValues" when in mix-mode
v4.9.6 (2022-02-07)
- minor syntax and comments changes
- added "help with something" issue templates
- fixes - Unable to edit tags when they reached to maxTags
- fixes - make the striped background on readonly an opt-out feature
- re-ordered classNames
- added "readonly" to be able to be configured from the settings and not only as an attribute on the original input
- fixes - dropdown.enabled:false has no effect
- Fix typo
v4.9.5 (2022-01-25)
- Fixed bugs
v4.9.2 (2021-11-28)
- add callback moved to be triggered after DOM has been modified
- tag is set as readonly even though tagData has key readonly:false
v4.9.1 (2021-11-20)
- fixed: readonly tag may be deleted in *mix-mode *
v4.9.0 (2021-11-14)
- React: switched to using the unminified Tagify for easier debugging
- fixes - [feat] added ther ability to persist data on localstorage automatically using a unique id per-instance
- no need to place loadOriginalValues within a setTimeout because it's automatically fired from "observeOriginalInputValue"
- fixes- Distribute non-minified code on NPM
- fixes - Dropdown selection in edited tag with emptied value fails
- fixes - move transformTag callback to be called before valitation happens
- fixes - Input is enabled in disabled mode
- minor fix for some random console error
- fixes - Placeholder text only shows when the page first loads
v4.8.1 (2021-09-25)
- Fixed bugs
v4.8.0 (2021-09-22)
- Fixes various bugs regarding mix-mode backspace & ENTER both in Chrome & FF.
v4.7.2 (2021-08-23)
- Bugfix: Extra newlines added on double Enter
v4.7.1 (2021-08-22)
- Added dropdown.toggle method
- Fixes an issue with "userInput" setting - when a tag is selected the dropdown is closed bu the component still has focus so clicking it again will not re-open then dropdown. Must force enabled to 0 to solve this.
v4.7.0 (2021-08-21)
- fixed: mix-mode with tags, when caret at the end and pessing Delete a few times, tags should not be removed
- fixed: mix-mode with simple whitelist & "dropdown.enabled = 0" setting could not select suggestions after only typing the pattern
- fixed: added "userInput" setting ("true" by default) which allows typing/pasting/editing tags
- updated Codepen CSS for toggling original input visibility
- fixed: removed IE support
- fixed: when allowing duplicates, duplicates are not matched with the filtered whitelist
- fixed: allows Select mode to not be editable if "enforceWhitelist" setting is set, and also allows backspace to remove selected tag
- select-mode with "enforceWhitelist" setting should not be editable
- improved "advanced options" example so a single click will change to a random tag color
v4.6.0 (2021-07-29)
- Add mechanism to unbind all global event listeners of an instance
- Refactored "texts" for easier customization from "settings"
- Fixed bugs.
v4.5.0 (2021-07-14)
- Briefly show knobs before closing it
- Improved the "easy to customize" section in the demo page with link to CSS variables
- fixed missing parts in code examples syntax highlighter in the demo page
- R efactored code for better supporting React components as templates
v4.4.0 (2021-07-04)
- Fixed bugs
v4.3.1 (2021-06-16)
- Minor bugfix for invalid edited tags' title tooltip
v4.3.0 (2021-06-13)
- fixed: backspace in 'mix' mode with multiple lines Previous lines are being hidden and removed from the text area
- [chore] refactored dropdown methods so they wouldn't need binding with "bind" or "call"
- [feature] added "whitelist" getter and setter directly on the instance
- fixed tags validation when edited/removed
- improved "isSameDeep" to not stringify if already is a string
- refactored "defaultValue" logic related to "value" changes
- small general refactor for all events binding
v4.2.0 (2021-06-07)
- Bugs fixed.
v4.1.4 (2021-05-31)
- restored missing header comment in minified files
- suggestions dropdown list now has scrollbar shown by default and no only on hover, for touch screen issues where "hover" cannot be applied
- fixed: revalidate max tags after tags are removed
v4.1.3 (2021-05-24)
- fixes - onInput event is fired too early, before a tag was added, so "tagify.value" is not up-to-date
- fixes - Re-validation on edit/delete tags
v4.1.2 (2021-05-16)
- fixed: retain invalid tags (including from page load) but color them red
This awesome jQuery plugin is developed by yairEO. For more Advanced Usages, please check the demo page or visit the official website.











