Basic

<input name='basic' value='tag1, tag2 autofocus'>
// The DOM element you wish to replace with Tagify
var input = document.querySelector('input[name=basic]');

// initialize Tagify on the above input node reference
new Tagify(input)

Mix Text & Tags

Use @ Symbol to add Programming language and # Symbol to add Companies. For Example - @v and #a

<textarea name='mix'>Hello, My name is [[Shaun]]. I am a [[{"id": 100, "text": "React", "title": "facebook"}]] Developer. I am currently working in [[{"value":"Microsoft"}]]</textarea>
/**
* 
* Mix Text & Tags
*  
**/ 

// Define two types of whitelists, each used for the dropdown suggestions menu,
// depending on the prefix pattern typed (@/#). See settings below.
var whitelist_1 = [
{ value: 100, text: 'React', title: 'facebook' },
{ value: 200, text: 'Vue', title: 'Kelly Young' },
{ value: 300, text: 'Angular', title: 'Google' },
{ value: 400, text: 'Svelte', title: 'Rich Harris' },
{ value: 500, text: 'NextJS', title: 'Vercel' },
{ value: 600, text: 'Python', title: 'Guido van Rossum' },
{ value: 700, text: 'PHP', title: 'Rasmus Lerdorf' },
{ value: 800, text: 'Strapi', title: 'Open Source' },
{ value: 900, text: 'Wordpress', title: 'Automatic' },
{ value: 1000, text: 'Typescript', title: 'Microsoft' }
]

// Second whitelist, which is shown only when starting to type "#".
// Thiw whitelist is the most simple one possible.
var whitelist_2 = ['Microsoft', 'Apple', 'Google', 'Samsung', 'Esty', 'Github', 'Amazon', 'Ebay', 'FedEx', 'Facebook'];


// initialize Tagify
var input = document.querySelector('[name=mix]'),
// init Tagify script on the above inputs
mixMatch = new Tagify(input, {
mode: 'mix',  // <--  Enable mixed-content
pattern: /@|#/,  // <--  Text starting with @ or # (if single, String can be used here)
tagTextProp: 'text',  // <-- the default property (from whitelist item) for the text to be rendered in a tag element.
// Array for initial interpolation, which allows only these tags to be used
whitelist: whitelist_1.concat(whitelist_2).map(function(item){
return typeof item == 'string' ? {value:item} : item
}),
dropdown : {
enabled: 1,
position: 'text', // <-- render the suggestions list next to the typed text ("caret")
mapValueTo: 'text', // <-- similar to above "tagTextProp" setting, but for the dropdown items
highlightFirst: true  // automatically highlights first sugegstion item in the dropdown
},
callbacks: {
add: console.log,  // callback when adding a tag
remove: console.log   // callback when removing a tag
}
})


// A good place to pull server suggestion list accoring to the prefix/value
mixMatch.on('input', function(e){
var prefix = e.detail.prefix;

// first, clean the whitlist array, because the below code, while not, might be async,
// therefore it should be up to you to decide WHEN to render the suggestions dropdown
// tagify.settings.whitelist.length = 0;

if( prefix ){
if( prefix == '@' )
mixMatch.whitelist = whitelist_1;

if( prefix == '#' )
mixMatch.whitelist = whitelist_2;

if( e.detail.value.length > 1 )
mixMatch.dropdown.show(e.detail.value);
}

console.log( mixMatch.value )
console.log('mix-mode "input" event value: ', e.detail)
})

mixMatch.on('add', function(e){
console.log(e)
})

Suggestions List

Search Languages with there First Capital Letter For Example: JSON with J

<input name='tags3' value='[{"value":"React"}, {"value":"Angular"}]' pattern='^[A-Za-z_✲ ]{1,15}$'>
/**
* 
* Render Suggestion
*  
**/ 

var input = document.querySelector('input[name=tags3]'),
tagify = new Tagify(input, {
pattern             : /^.{0,20}$/,  // Validate typed tag(s) by Regex. Here maximum chars length is defined as "20"
delimiters          : ",| ",        // add new tags when a comma or a space character is entered
keepInvalidTags     : true,         // do not remove invalid tags (but keep them marked as invalid)
editTags            : {
clicks: 2,              // single click to edit a tag
keepInvalid: false      // if after editing, tag is invalid, auto-revert
},
maxTags             : 6,
blacklist           : ["foo", "bar", "baz"],
whitelist           : ["React","Angular","TypeScript","Vue","Python","Wordpress","Svelte","PHP","Javascript","HTML","CSS","JSON","XML","Markdown","Go","C++","C#","Java","Docker","Perl","Ruby","Rust","NodeJS","SQL","SQLite","MonogDB","MYSQL","Swift","SCSS","SASS"],
transformTag        : transformTag,
backspace           : "edit",
placeholder         : "Type something",
dropdown : {
enabled: 1,            // show suggestion after 1 typed character
fuzzySearch: false,    // match only suggestions that starts with the typed characters
position: 'text',      // position suggestions list next to typed text
caseSensitive: true,   // allow adding duplicate items if their case is different
},
templates: {
dropdownItemNoMatch: function(data) {
return `<div class='${this.settings.classNames.dropdownItem}' tabindex="0" role="option">
No suggestion found for: <strong>${data.value}</strong>
</div>`
}
}
})

// generate a random color (in HSL format, which I like to use)
function getRandomColor(){
function rand(min, max) {
return min + Math.random() * (max - min);
}

var h = rand(1, 360)|0,
s = rand(40, 70)|0,
l = rand(65, 72)|0;

return 'hsl(' + h + ',' + s + '%,' + l + '%)';
}

function transformTag( tagData ){
tagData.color = getRandomColor();
tagData.style = "--tag-bg:" + tagData.color;

if( tagData.value.toLowerCase() == 'shit' )
tagData.value = 's✲✲t'
}

tagify.on('add', function(e){
console.log(e.detail)
})

tagify.on('invalid', function(e){
console.log(e, e.detail);
})

var clickDebounce;

tagify.on('click', function(e){
const {tag:tagElm, data:tagData} = e.detail;

// a delay is needed to distinguish between regular click and double-click.
// this allows enough time for a possible double-click, and noly fires if such
// did not occur.
clearTimeout(clickDebounce);
clickDebounce = setTimeout(() => {
tagData.color = getRandomColor();
tagData.style = "--tag-bg:" + tagData.color;
tagify.replaceTag(tagElm, tagData);
}, 200);
})

tagify.on('dblclick', function(e){
// when souble clicking, do not change the color of the tag
clearTimeout(clickDebounce);
})

Users List

<input name='users-list-tags' value='abatisse2@nih.gov, Justinian Hattersley'>
/**
* 
* Users List
*  
**/ 


// https://www.mockaroo.com/


var inputElm = document.querySelector('input[name=users-list-tags]');

function tagTemplate(tagData){
return `
<tag title="${tagData.email}"
contenteditable='false'
spellcheck='false'
tabIndex="-1"
class="tagify__tag ${tagData.class ? tagData.class : ""}"
${this.getAttributes(tagData)}>
<x title='' class='tagify__tag__removeBtn' role='button' aria-label='remove tag'></x>
<div>
<div class='tagify__tag__avatar-wrap'>
    <img onerror="this.style.visibility='hidden'" src="${tagData.avatar}">
</div>
<span class='tagify__tag-text'>${tagData.name}</span>
</div>
</tag>
`
}

function suggestionItemTemplate(tagData){
return `
<div ${this.getAttributes(tagData)}
class='tagify__dropdown__item ${tagData.class ? tagData.class : ""}'
tabindex="0"
role="option">
${ tagData.avatar ? `
<div class='tagify__dropdown__item__avatar-wrap'>
<img onerror="this.style.visibility='hidden'" src="${tagData.avatar}">
</div>` : ''
}
<strong>${tagData.name}</strong>
<span>${tagData.email}</span>
</div>
`
}

// initialize Tagify on the above input node reference
var usrList = new Tagify(inputElm, {
tagTextProp: 'name', // very important since a custom template is used with this property as text
enforceWhitelist: true,
skipInvalid: true, // do not remporarily add invalid tags
dropdown: {
closeOnSelect: false,
enabled: 0,
classname: 'users-list',
searchKeys: ['name', 'email']  // very important to set by which keys to search for suggesttions when typing
},
templates: {
tag: tagTemplate,
dropdownItem: suggestionItemTemplate
},
whitelist: [
{
"value": 1,
"name": "Justinian Hattersley",
"avatar": "https://i.pravatar.cc/80?img=1",
"email": "jhattersley0@ucsd.edu"
},
{
"value": 2,
"name": "Antons Esson",
"avatar": "https://i.pravatar.cc/80?img=2",
"email": "aesson1@ning.com"
},
{
"value": 3,
"name": "Ardeen Batisse",
"avatar": "https://i.pravatar.cc/80?img=3",
"email": "abatisse2@nih.gov"
},
{
"value": 4,
"name": "Graeme Yellowley",
"avatar": "https://i.pravatar.cc/80?img=4",
"email": "gyellowley3@behance.net"
},
{
"value": 5,
"name": "Dido Wilford",
"avatar": "https://i.pravatar.cc/80?img=5",
"email": "dwilford4@jugem.jp"
},
{
"value": 6,
"name": "Celesta Orwin",
"avatar": "https://i.pravatar.cc/80?img=6",
"email": "corwin5@meetup.com"
},
{
"value": 7,
"name": "Sally Main",
"avatar": "https://i.pravatar.cc/80?img=7",
"email": "smain6@techcrunch.com"
},
{
"value": 8,
"name": "Grethel Haysman",
"avatar": "https://i.pravatar.cc/80?img=8",
"email": "ghaysman7@mashable.com"
},
{
"value": 9,
"name": "Marvin Mandrake",
"avatar": "https://i.pravatar.cc/80?img=9",
"email": "mmandrake8@sourceforge.net"
},
{
"value": 10,
"name": "Corrie Tidey",
"avatar": "https://i.pravatar.cc/80?img=10",
"email": "ctidey9@youtube.com"
},
{
"value": 11,
"name": "foo",
"avatar": "https://i.pravatar.cc/80?img=11",
"email": "foo@bar.com"
},
{
"value": 12,
"name": "foo",
"avatar": "https://i.pravatar.cc/80?img=12",
"email": "foo.aaa@foo.com"
},
]
})

usrList.on('dropdown:show dropdown:updated', onDropdownShow)
usrList.on('dropdown:select', onSelectSuggestion)

var addAllSuggestionsElm;

function onDropdownShow(e){
var dropdownContentElm = e.detail.tagify.DOM.dropdown.content;

if( usrList.suggestedListItems.length > 1 ){
addAllSuggestionsElm = getAddAllSuggestionsElm();

// insert "addAllSuggestionsElm" as the first element in the suggestions list
dropdownContentElm.insertBefore(addAllSuggestionsElm, dropdownContentElm.firstChild)
}
}

function onSelectSuggestion(e){
if( e.detail.elm == addAllSuggestionsElm )
usrList.dropdown.selectAll();
}

// create a "add all" custom suggestion element every time the dropdown changes
function getAddAllSuggestionsElm(){
// suggestions items should be based on "dropdownItem" template
return usrList.parseTemplate('dropdownItem', [{
class: "addAll",
name: "Add all",
email: usrList.whitelist.reduce(function(remainingSuggestions, item){
return usrList.isTagDuplicate(item.value) ? remainingSuggestions : remainingSuggestions + 1
}, 0) + " Members"
}]
)
}

Single Value Select

<input name='tags-select-mode' class='selectMode' placeholder="Please select" />
/**
* 
*  Single Value Select
* 
*/

var input = document.querySelector('input[name=tags-select-mode]'),
tagify = new Tagify(input, {
enforceWhitelist: true,
mode : "select",
whitelist: ["first option", "second option", "third option"],
blacklist: ['foo', 'bar'],
})

// bind events
tagify.on('add', onAddTag)
tagify.DOM.input.addEventListener('focus', onSelectFocus)

function onAddTag(e){
console.log(e.detail)
}

function onSelectFocus(e){
console.log(e)
}