@cybk/tagify
v4.9.9
Published
lightweight, efficient Tags input component in Vanilla JS / React / Angular [super customizable, tiny size & top performance]- custom implementation with transpilled distibution file
Downloads
10
Readme
Table of Contents
- Table of Contents
- Installation
- Features
- Building the project
- Adding tags dynamically
- Output value
- Ajax whitelist
- Persisted data
- Edit tags
- Validations
- Drag & Sort
- DOM Templates
- Suggestions list
- Mixed-Content
- Single-Value
- React
- jQuery version
- CSS Variables
- Methods
- Events
- Hooks
- Settings
Installation
Option 1 - import from CDN:
Place these lines before any other code which is (or will be) using Tagify (Example here)
<script src="https://unpkg.com/@yaireo/tagify"></script>
<script src="https://unpkg.com/@yaireo/tagify/dist/tagify.polyfills.min.js"></script>
<link href="https://unpkg.com/@yaireo/tagify/dist/tagify.css" rel="stylesheet" type="text/css" />
Tagify
will then be available globally.
To load specific version use @
- for example: unpkg.com/@yaireo/[email protected]
option 2 - import as a Node module:
npm i @yaireo/tagify --save
Usage (in your bundle):
live demo using Parcel as bundler
import Tagify from '@yaireo/tagify'
var tagify = new Tagify(...)
Don't forget to include
tagify.css
file in your project. CSS location:@yaireo/tagify/dist/tagify.css
SCSS location:@yaireo/tagify/src/tagify.scss
See SCSS usecase & example
Features
- Can be applied on input & textarea elements
- Supports mix content (text and tags together)
- Supports single-value mode (like
<select>
) - Supports whitelist/blacklist
- Supports Templates for: component wrapper, tag items, suggestion list & suggestion items
- Shows suggestions list (flexiable settings & styling) at full (component) width or next to the typed texted (caret)
- Allows setting suggestions' aliases for easier fuzzy-searching
- Auto-suggest input as-you-type with ability to auto-complete
- Can paste in multiple values:
tag 1, tag 2, tag 3
or even newline-separated tags - Tags can be created by Regex delimiter or by pressing the "Enter" key / focusing of the input
- Validate tags by Regex pattern or by function
- Tags may be editable (double-click)
- ARIA accessibility support(Component too generic for any meaningful ARIA)
- Supports read-only mode to the whole componenet or per-tag
- Each tag can have any properties desired (class, data-whatever, readonly...)
- Automatically disallow duplicate tags (vis "settings" object)
- Has built-in CSS loader, if needed (Ex. AJAX whitelist pulling)
- Tags can be trimmed via
hellip
by givingmax-width
to thetag
element in yourCSS
- Easily change direction to RTL (via the SCSS file)
- Internet Explorer - A polyfill script should be used:
tagify.polyfills.min.js
(in/dist
) (IE support has been dropped) - Many useful custom events
- Original input/textarea element values kept in sync with Tagify
Building the project
Simply run gulp
in your terminal, from the project's path (Gulp should be installed first).
Source files are this path: /src/
Output files, which are automatically generated using Gulp, are in: /dist/
The rest of the files are most likely irrelevant.
Adding tags dynamically
var tagify = new Tagify(...);
tagify.addTags(["banana", "orange", "apple"])
// or add tags with pre-defined propeties
tagify.addTags([{value:"banana", color:"yellow"}, {value:"apple", color:"red"}, {value:"watermelon", color:"green"}])
Output value
There are two possible ways to get the value of the tags:
- Access the tagify's instance's
value
prop:tagify.value
(Array of tags) - Access the original input's value:
inputElm.value
(Stringified Array of tags)
The most common way is to simply listen to the change
event on the original input
var inputElm = document.querySelector,
tagify = new Tagify (inputElm);
inputElm.addEventListener('change', onChange)
function onChange(e){
// outputs a String
console.log(e.target.value)
}
Modify original input value format
Default format is a JSON string:
'[{"value":"cat"}, {"value":"dog"}]'
I recommend keeping this because some situations might have values such as addresses (tags contain commas):
'[{"value":"Apt. 2A, Jacksonville, FL 39404"}, {"value":"Forrest Ray, 191-103 Integer Rd., Corona New Mexico"}]'
Another example for complex tags state might be disabled tags, or ones with custom identifier class:
(tags can be clicked, so delevopers can choose to use this to disable/enable tags)
'[{"value":"cat", "disabled":true}, {"value":"dog"}, {"value":"bird", "class":"color-green"}]'
To change the format, assuming your tags have no commas and are fairly simple:
var tagify = new Tagify(inputElm, {
originalInputValueFormat: valuesArr => valuesArr.map(item => item.value).join(',')
})
Output:
"cat,dog"
Ajax whitelist
Dynamically-loaded suggestions list (whitelist) from the server (as the user types) is a frequent need to many.
Tagify comes with its own loading animation, which is a very lightweight CSS-only code, and the loading
state is controlled by the method tagify.loading
which accepts true
or false
as arguments.
Below is a basic example using the fetch
API. I advise to abort the last request on any input before starting a new request.
var input = document.querySelector('input'),
tagify = new Tagify(input, {whitelist:[]}),
controller; // for aborting the call
// listen to any keystrokes which modify tagify's input
tagify.on('input', onInput)
function onInput( e ){
var value = e.detail.value
tagify.whitelist = null // reset the whitelist
// https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort
controller && controller.abort()
controller = new AbortController()
// show loading animation and hide the suggestions dropdown
tagify.loading(true).dropdown.hide()
fetch('http://get_suggestions.com?value=' + value, {signal:controller.signal})
.then(RES => RES.json())
.then(function(newWhitelist){
tagify.whitelist = newWhitelist // update whitelist Array in-place
tagify.loading(false).dropdown.show(value) // render the suggestions dropdown
})
}
Persisted data
Sometimes the whitelist might be loaded asynchronously, and so any pre-filled value in the original input field
will be removed if the enforceWhitelist
is set to true
.
Tagify can automatically restore the last used whitelist
by setting a unique id to the Tagify instance,
by using the localstorage to persist the whitelist
& value
data:
var input = document.querySelector('input'),
tagify = new Tagify(input, {
id: 'test1', // must be unique (per-tagify instance)
enforceWhitelist: true,
}),
Edit tags
Tags which aren't read-only
can be edited by double-clicking them (by default)
or by changing the editTags
setting to 1
, making tags editable by single-clicking them.
The value is saved on blur
or by pressing enter
key. Pressing Escape
will revert the change trigger blur
.
ctrlz will revert the change if an edited tag was marked as not valid (perhaps duplicate or blacklisted)
To prevent all tags from being allowed to be editable, set the editTags
setting to false
(or null
).
To do the same but for specific tag(s), set those tags' data with editable
property set to false
:
<input value='[{"value":"foo", "editable":false}, {"value":"bar"}]'>
Validations
For "regular" tags (not mix-mode or select-mode) the easiest way is to use the pattern
setting and use a Regex, or
apply the pattern
attribute directly on the input
which will be "transformed" into a Tagify component (for vanilla code where the input
tag is fully accessible to develops).
If the pattern
setting does not meet your needs, use the validate
setting, which recieves a tag data object as an argument and should return true
if validaiton is passing, or false
/string
of not.
A string may be returned as the reason of the validation failure so it would be printed as the title
attribute of the invalid tag.
Note - there is a setting to keep invalid tags (keepInvalidTags
) and if it's set to true
, the user can see the reason for the invalidation by
hovering the tag and see the browser's native tooltip via the title
attribute:
{
empty : "empty",
exceed : "number of tags exceeded",
pattern : "pattern mismatch",
duplicate : "already exists",
notAllowed : "not allowed"
}
The texts for those (invalid tags) titles can be customized from the settings:
new Tagify(inputElement, {
texts: {
duplicate: "Duplicates are not allowed"
}
})
Or by directly manipulating the Tagify function prototype:
Tagify.prototype.TEXTS = {...Tagify.prototype.TEXTS, {duplicate: "Duplicates are not allowed"}}
Drag & Sort
To be able to sort tags by draging, a 3rd-party script is needed.
I have made a very simple drag & drop (~11kb
unminified) script which uses HTML5 native API and
it is available to download via NPM or Github
but any other drag & drop script may possibly work. I could not find in the whole internet a decent lightweight script.
Integration example:
var tagify = new Tagify(inputElement)
// bind "DragSort" to Tagify's main element and tell
// it that all the items with the below "selector" are "draggable"
var dragsort = new DragSort(tagify.DOM.scope, {
selector: '.'+tagify.settings.classNames.tag,
callbacks: {
dragEnd: onDragEnd
}
})
// must update Tagify's value according to the re-ordered nodes in the DOM
function onDragEnd(elm){
tagify.updateValueByDOMTags()
}
DOM Templates
It's possible to control the templates for some of the HTML elements tagify is using by
modifying the settings.templates
Object with your own custom functions which must return an HTML string.
Available templates are: wrapper
, tag
, dropdown
, dropdownItem
and the optional dropdownItemNoMatch
which is a special template for rendering a suggestion item (in the dropdown list) only if there were no matches found for the typed input.
Example of overriding the tag
template:
Each template function automaticaly gets binded with this
pointing to the current Tagify instance.
It is imperative to preserve the class names and also the this.getAttributes(tagData)
for proper functionality.
new Tagify(inputElem, {
templates: {
tag(tagData, tagify){
return `<tag title="${(tagData.title || tagData.value)}"
contenteditable='false'
spellcheck='false'
tabIndex="${this.settings.a11y.focusableTags ? 0 : -1}"
class="${this.settings.classNames.tag} ${tagData.class ? tagData.class : ""}"
${this.getAttributes(tagData)}>
<x title='' class="${this.settings.classNames.tagX}" role='button' aria-label='remove tag'></x>
<div>
<span class="${this.settings.classNames.tagText}">${tagData[this.settings.tagTextProp] || tagData.value}</span>
</div>
</tag>`
}
})
Suggestions list
The suggestions list is a whitelist Array of Strings or Objects which was set in the settings Object when the Tagify instance was created, and can be set latet directly on the instance: tagifyInstance.whitelist = ["tag1", "tag2", ...]
.
The suggestions dropdown will be appended to the document's <body>
element and will be rendered by default in a position below (bottom of) the Tagify element.
Using the keyboard arrows up/down will highlight an option from the list, and hitting the Enter key to select.
It is possible to tweak the list dropdown via 2 settings:
enabled
- this is a numeral value which tells Tagify when to show the suggestions dropdown, when a minimum of N characters were typed.maxItems
- Limits the number of items the suggestions list will render
var input = document.querySelector('input'),
tagify = new Tagify(input, {
whitelist : ['aaa', 'aaab', 'aaabb', 'aaabc', 'aaabd', 'aaabe', 'aaac', 'aaacc'],
dropdown : {
classname : "color-blue",
enabled : 0, // show the dropdown immediately on focus
maxItems : 5,
position : "text", // place the dropdown near the typed text
closeOnSelect : false, // keep the dropdown open after selecting a suggestion
highlightFirst: true
}
});
<div class="tagify__dropdown tagify__dropdown--text" style="left:993.5px; top:106.375px; width:616px;">
<div class="tagify__dropdown__wrapper">
<div class="tagify__dropdown__item tagify__dropdown__item--active" value="aaab">aaab</div>
<div class="tagify__dropdown__item" value="aaabb">aaabb</div>
<div class="tagify__dropdown__item" value="aaabc">aaabc</div>
<div class="tagify__dropdown__item" value="aaabd">aaabd</div>
<div class="tagify__dropdown__item" value="aaabe">aaabe</div>
</div>
</div>
By default searching the suggestions is using fuzzy-search (see settings).
If you wish to assign alias to items (in your suggestion list), add the searchBy
property to whitelist items you wish
to have an alias for.
In the below example, typing a part of a string which is included in the searchBy
property, for example land midd"
-
the suggested item which match the value "Israel" will be rendered in the suggestions (dropdown) list.
Example for a suggestion item alias
whitelist = [
...
{ value:'Israel', code:'IL', searchBy:'holy land, desert, middle east' },
...
]
Another handy setting is dropdown.searchKeys
which, like the above dropdown.searchBy
setting, allows
expanding the search of any typed terms to more than the value
property of the whitelist items (if items are a Collection).
Example whitelist:
[
{
value : 123456,
nickname : "foo",
email : "[email protected]"
},
{
value : 987654,
nickname : "bar",
email : "[email protected]"
},
...more..
]
// setting to search in other keys:
{
dropdown: {
searchKeys: ["nickname", "email"] // fuzzy-search matching for those whitelist items' properties
}
}
Mixed-Content
This feature must be toggled using these settings:
{
// mixTagsInterpolator: ["{{", "}}"], // optional: interpolation before & after string
mode: 'mix', // <-- Enable mixed-content
pattern: /@|#/ // <-- Text starting with @ or # (if single, String can be used here instead of Regex)
}
When mixing text with tags, the original textarea (or input) element will have a value as follows:
[[cartman]] and [[kyle]] do not know [[Homer simpson]]
If the inital value of the textarea or input is formatted as the above example, tagify will try to
automatically convert everything between [[
& ]]
to a tag, if tag exists in the whitelist, so make
sure when the Tagify instance is initialized, that it has tags with the correct value
property that match
the same values that appear between [[
& ]]
.
Applying the setting dropdown.position:"text"
is encouraged for mixed-content tags, because the suggestions list
weird when there is already a lot of content at multiple lines.
If a tag does not exists in the whitelist, it may be created by the user and all you should do is listen to the add
event and update your local/remote state.
Single-Value
Similar to native <Select>
element, but allows typing text as value.
React
See live demo for React integration examples. ⚠️ Tagify is not a controlled component.
A Tagify React component is exported from react.tagify.js
:
Update regarding onChange
prop:
I have changed how the onChange
works internally within the Wrapper of Tagify
so as of March 30, 2021 the e
argument will include a detail
parameter with the value as string.
There is no more e.target
, and to access the original DOM input element, do this: e.detail.tagify.DOM.originalInput
.
Note: You will need to import Tagify's CSS also, either by JavaScript or by SCSS
@import
(which is preferable) Also note that you will need to use dart-sass and not node-sass in order to compile the file.
import Tags from "@yaireo/tagify/dist/react.tagify" // React-wrapper file
import "@yaireo/tagify/dist/tagify.css" // Tagify CSS
// on tag add/edit/remove
const onChange = useCallback((e) => {
console.log("CHANGED:"
, e.detail.tagify.value // Array where each tag includes tagify's (needed) extra properties
, e.detail.tagify.getCleanValue()) // Same as above, without the extra properties
, e.detail.value // a string representing the tags
)
}, [])
const App = () => {
return (
<Tags
tagifyRef={tagifyRef} // optional Ref object for the Tagify instance itself, to get access to inner-methods
settings={settings} // tagify settings object
defaultValue="a,b,c"
{...tagifyProps} // dynamic props such as "loading", "showDropdown:'abc'", "value"
onChange={onChange}
/>
)
})
To gain full access to Tagify's (instance) inner methods, A custom ref
can be used:
...
const tagifyRef = useRef()
...
<Tags tagifyRef={tagifyRef} ... />
// or mix-mode
<MixedTags
settings={...}
onChange={...}
defaultValue={`This is a textarea which mixes text with [[{"value":"tags"}]].`}
/>
<MixedTags>
component is a shorthand for <Tags InputMode="textarea">
Updating the component's state
The settings
prop is only used once in the initialization process, please do not update it afterwards.
Prop | Type | Updatable | Info
----------------------- | ------------------------- |:---------:| -----------------------------------------------------------
settings | Object | | See settings section
name | String | ✔ | <input>
's element name
attribute
value | String/Array | ✔ | Initial value.
defaultValue | String/Array | | Same as value prop
placeholder | <sub>String</sub> | ✔ | placeholder text for the component
readOnly | <sub>Boolean</sub> | ✔ | Toggles
readonlystate. With capital
O.
tagifyRef | <sub>Object</sub> | |
useRefhook refference for the component inner instance of vailla *Tagify* (for methods access)
showFilteredDropdown | <sub>Boolean/String</sub> | ✔ | if
trueshows the suggestions dropdown. if assigned a String, show the dropdown pre-filtered.
loading | <sub>Boolean</sub> | ✔ | Toggles
loadingstate for the whole component
whitelist | <sub>Array</sub> | ✔ | Sets the
whitelistwhich is the basis for the suggestions dropdown & autocomplete
className | <sub>String</sub> | | Component's optional class name to be added
InputMode | <sub>String</sub> | |
"textarea"will create a
(hidden) element instead of the default
and automatically make Tagify act as [*"mix mode"*](#mixed-content)
autoFocus | <sub>Boolean</sub> | | Should the component have focus on mount. Must be unique, per-page.
children | <sub>String/Array</sub> | |
value/
defaultValue` props are prefered
onChange | Function | | See events section
onInput | Function | | See events section
onAdd | Function | | See events section
onRemove | Function | | See events section
onInvalid | Function | | See events section
onClick | Function | | See events section
onKeydown | Function | | See events section
onFocus | Function | | See events section
onBlur | Function | | See events section
onEditInput | Function | | See events section
onEditBeforeUpdate | Function | | See events section
onEditUpdated | Function | | See events section
onEditStart | Function | | See events section
onEditKeydown | Function | | See events section
onDropdownShow | Function | | See events section
onDropdownHide | Function | | See events section
onDropdownSelect | Function | | See events section
onDropdownScroll | Function | | See events section
onDropdownNoMatch | Function | | See events section
onDropdownUpdated | Function | | See events section
jQuery version
jQuery.tagify.js
A jQuery wrapper verison is also available, but I advise not using it because it's basically the exact same as the "normal" script (non-jqueryfied) and all the jQuery's wrapper does is allowing to chain the event listeners for ('add', 'remove', 'invalid')
$('[name=tags]')
.tagify()
.on('add', function(e, tagData){
console.log('added', ...tagData) // data, index, and DOM node
});
Accessing methods can be done via the .data('tagify')
:
$('[name=tags]').tagify();
// get tags from the server (ajax) and add them:
$('[name=tags]').data('tagify').addTags('aaa, bbb, ccc')
HTML input & textarea attributes
The below list of attributes affect Tagify. These can also be set by Tagify settings Object manually, and not declerativly (via attributes).
Attribute | Example | Info
----------------- | ----------------------------------------------------- | --------------------
pattern | <input pattern='^[A-Za-z_✲ ]{1,15}$'>
| Tag Regex pattern which tag input is validated by.
placeholder | <input placeholder='please type your tags'>
| This attribute's value will be used as a constant placeholder, which is visible unless something is being typed.
readOnly | <input readOnly>
| No user-interaction (add/remove/edit) allowed.
autofocus | <input autofocus>
| Automatically focus the the Tagify component when the component is loaded
required | <input required>
| Adds a required
attribute to the Tagify wrapper element. Does nothing more.
FAQ
List of questions & scenarios which might come up during development with Tagify:
const tagify = new Tagify(tagNode, {
whitelist: ["a", "b", "c"]
})
If changes to the whitelist are needed, they should be done like so:
Incorrect:
tagify.settings.whitelist = ["foo", "bar"]
Correct:
// set the whitelist directly on the instance and not on the "settings" property
tagify.whitelist = ["foo", "bar"]
Tagify does not accept just any kind of data structure.
If a tag data is represented as an Object
, it must contain a unique property value
which Tagify uses to check if a tag already exists, among other things, so make sure it is present.
Incorrect:
[{ "id":1, "name":"foo bar" }]
Correct:
[{ "id":1, "value": 1, "name":"foo bar" }]
[{ "value":1, "name":"foo bar" }]
[{ "value":"foo bar" }]
// ad a simple array of Strings
["foo bar"]
In framework-less projects, the developer should save the state of the Tagify component (somewhere), and
the question is:
when should the state be saved?
On every change made to Tagify's internal state (tagify.value
via the update()
method).
var tagify = new Tagify(...)
// listen to "change" events on the "original" input/textarea element
tagify.DOM.originalInput.addEventListener('change', onTagsChange)
// This example uses async/await but you can use Promises, of course, if you prefer.
async function onTagsChange(e){
const {name, value} = e.target
// "imaginary" async function "saveToServer" should get the field's name & value
await saveToServer(name, value)
}
If you are using React/Vue/Angular or any "modern" framework, then you already know how to
attach "onChange" event listeners to your <input>
/<textarea>
elements, so the above is irrelevant.
Stopping tags from wrapping to new lines, add this to your .tagify
selector CSS Rule:
flex-wrap: nowrap;
Tagify internally has state
property, per Tagify
instance
and this may be useful for a variety of things when implementing a specific scenario.
var tagify = new Tagify(...)
var formElm = document.forms[0]; // just an example
tagify.on('keydown', onTagifyKeyDown)
function onTagifyKeyDown(e){
if( e.key == 'Enter' && // "enter" key pressed
!tagify.state.inputText && // assuming user is not in the middle oy adding a tag
!tagify.state.editing // user not editing a tag
){
setTimeout(() => formElm.submit()) // put some buffer to make sure tagify has done with whatever, to be on the safe-side
}
}
- Double-click tag fires both "edit" & "click" custom events
- Manualy open the suggestions dropdown
- Render your own suggestions dropdown
- Allow max length on mix mode
- Always show dropdown
- Limit the length of a tag value (minimum & maximum)
- Mixed mode initial value
- Random colors for each tag
- Format input value for server side
- Writing to tagify textarea
- Scroll all tags within one line, instead of growing vertically
- Insert emoji at caret location when editing a tag
- propagate
change
event - Manually update tag data after it was added
- Ajax Whitelist with "enforceWhitelist" setting enabled
- Custom (multiple) tag validation & AJAX
- Make tags from pasted multi-line text
- Add a tag at caret position in mixed mode
- Change automatic title tooltips for invalid tags
CSS Variables
Learn more about CSS Variables) (custom properties)
Tagify's utilizes CSS variables which allow easy customization without the need to manually write CSS. If you do wish to heavily style your Tagify components, then you can (and should) use the below variables within your modified styles as much as you can.
For a live example, see the demos page.
Name | Info
------------------------------- | --------------------------------
--tags-disabled-bg | Tag background color when disabled
--tags-border-color | The outer border color which surrounds tagify
--tags-hover-border-color | hover state
--tags-focus-border-color | focus state
--tag-bg | Tag background color
--tag-hover | Tag background color on hover (mouse)
--tag-text-color | Tag text color
--tag-text-color--edit | Tag text color when a Tag is being edited
--tag-pad | Tag padding, from all sides. Ex. .3em .5em
--tag--min-width | Minimum Tag width
--tag--max-width | Maximum tag width, which gets trimmed with hellip after
--tag-inset-shadow-size | This is the inner shadow size, which dictates the color of the Tags.It's important the size fits exactly to the tag.Change this if you change the --tag-pad
or fontsize.
--tag-invalid-color | For border color of edited tags with invalid value being typed into them
--tag-invalid-bg | Background color for invalid Tags.
--tag-remove-bg | Tag background color when hovering the ×
button.
--tag-remove-btn-color | Remove (×
) button text color
--tag-remove-btn-bg | Remove (×
) button background color
--tag-remove-btn-bg--hover | Remove (×
) button hover background color
--input-color | Input text color
--tag-hide-transition | Controls the transition property when a tag is removed. default is '.3s'
--placeholder-color | Placeholder text color
--placeholder-color-focus | Placeholder text color when Tagify has focus and no input was typed
--loader-size | Loading animation size. 1em
is pretty big, default is a bit less.
--readonly-striped | Either a value 1
or 0
can be used to toggle the striped diagonal background in readonly
Full list of Tagify's SCSS variables
Methods
Tagify
is prototype based and There are many methods, but I've chosen to list the most relevant ones:
Name | Parameters | Info
-------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------
destroy
| | Reverts the input element back as it was before Tagify was applied
removeAllTags
| | Removes all tags and resets the original input tag's value property
addTags
| Array
/String
/Object
tag(s) to addBoolean
clear input after addingBoolean
- skip adding invalids | Accepts a String (word, single or multiple with a delimiter), an Array of Objects (see above) or Strings.
addMixTags
| Array
/String
| Bypasses the normalization process in addTags
, forcefully adding tags at the last caret location or at the end, if there's no last caret location saved (at tagify.state.selection
)
removeTags
| Array
/HTMLElement
/String
tag(s) to removesilent
does not update the component's valuetranDuration
Transition duration (in ms
) | (#502) Remove single/multiple Tags. When nothing passed, removes last tag. silent
- A flag, which when turned on, does not remove any value and does not update the original input value but simply removes the tag from tagifytranDuration
- delay for animation, after which the tag will be removed from the DOM
addEmptyTag
| Object
(tagData
) | Create an empty tag (optionally with pre-defined data) and enters "edit" mode directly. See demo
loadOriginalValues
| String
/Array
| Converts the input's value into tags. This method gets called automatically when instansiating Tagify. Also works for mixed-tags
getWhitelistItemsByValue
| Object
| {value}
- return an Array of found matching items (case-insensitive)
getTagIndexByValue
| String
| Returns the index of a specific tag, by value
getTagElmByValue
| String
| Returns the first matched tag node, if found
isTagDuplicate
| String
| Returns how many tags already exists with that value
parseMixTags
| String
| Converts a String argument ([[foo]] and [[bar]] are..
) into HTML with mixed tags & texts
getTagElms
| | Returns a DOM nodes list of all the tags
getTagElmByValue
| String
| Returns a specific tag DOM node by value
tagData
| HTMLElement
, Object
| set/get tag data on a tag element (has.tagify__tag
class by default)
editTag
| HTMLElement
| Goes to edit-mode in a specific tag
replaceTag
| tagElm
, Object
(tagData
) | Exit a tag's edit-mode. if "tagData" exists, replace the tag element with new data and update Tagify value
loading
| Boolean
| toggle loading state on/off (Ex. AJAX whitelist pulling)
tagLoading
| HTMLElement
, Boolean | same as above but for a specific tag element
createTagElem
| Object
(tagData
) | Returns a tag element from the supplied tag data
injectAtCaret
| HTMLElement
(injectedNode
), Object
(range
) | Injects text or HTML node at last caret position. range
parameter is optional
placeCaretAfterNode
| HTMLElement
| Places the caret after a given node
insertAfterTag
| HTMLElement
(tag element), HTMLElement
/String
(whatever to insert after) |
toggleClass
| Boolean
| Toggles class
on the main tagify container (scope
)
dropdown.selectAll
| | Add all whitelist items as tags and close the suggestion dropdown
dropdown.show
| String
| Shows the sugegstions list dropdown. A string paramater allows filtering the results
dropdown.hide
| Boolean
| Hides the suggestions list dropdown (if it's not managed manually by the developer)
dropdown.toggle
| Boolean
| Toggles dropdown show/hide. the boolean parameter will force-show
updateValueByDOMTags
| | Iterate tag DOM nodes and re-build the tagify.value
array (call this if tags get sorted manually)
parseTemplate
| String
/Function
(template name or function), Array
(data) | converts a template string (by selecting one from the settings.templates
by name or supplying a template function which returns a String) into a DOM node
setReadonly
| Boolean
| Toggles "readonly" mode on/off
setDisabled
| Boolean
| Toggles "disabled" mode on/off
getPersistedData
| String
| Get data for the specific instance by parameter
setPersistedData
| *
, String
| Set data for the specific instance. Must supply a second parameter which will be the key to save the data in the localstorage (under the tagify namespace)
clearPersistedData
| String
| Clears data for the specific instance, by parameter. If the parameter is ommited, clears all persisted data related to this instance (by its id
which was set in the instance's settings)
Events
All triggered events return the instance's scope (tagify).
See e.detail
for custom event additional data.
var tagify = new Tagify(...)
// events can be chainable, and multiple events may be binded for the same callback
tagify
.on('input', e => console.log(e.detail))
.on('edit:input edit:updated edit:start edit:keydown', e => console.log(e.type, e.detail))
var tagify = new Tagify(inputNode, {
callbacks: {
"change": (e) => console.log(e.detail),
"dropdown:show": (e) => console.log(e.detail)
}
})
Name | Info
------------------ | --------------------------------------------------------------------------
change | Any change to the value has occured. e.details.value
callback listener argument is a String
add | A tag has been added
remove | A tag has been removed (use removeTag
instead with jQuery)
invalid | A tag has been added but did not pass vaildation. See event detail
input | Input event, when a tag is being typed/edited. e.detail
exposes value
, inputElm
& isValid
click | Clicking a tag. Exposes the tag element, its index & data
dblclick | Double-clicking a tag
keydown | When tagify input has focus and a key was pressed
focus | The component currently has focus
blur | The component lost focus
edit:input | Typing inside an edited tag
edit:beforeUpdate | Just before a tag has been updated, while still in "edit" mode
edit:updated | A tag as been updated (changed view editing or by directly calling the replaceTag()
method)
edit:start | A tag is now in "edit mode"
edit:keydown | keydown event while an edited tag is in focus
dropdown:show | Suggestions dropdown is to be rendered. The dropdown DOM node is passed in the callback, see demo.
dropdown:hide | Suggestions dropdown has been removed from the DOM
dropdown:select | Suggestions dropdown item selected (by mouse/keyboard/touch)
dropdown:scroll | Tells the percentage scrolled. (event.detail.percentage
)
dropdown:noMatch | No whitelist suggestion item matched for the the typed input. At this point it is possible to manually set tagify.suggestedListItems
to any possible custom value, for example: [{ value:"default" }]
dropdown:updated | Fired when the dropdown list is re-filtered while suggestions list is visible and a tag was removed so it was re-added as a suggestion
Hooks
Promise-based hooks for async program flow scenarios.
Allows to "hook" (intervene) at certain points of the program, which were selected as a suitable place to pause the program flow and wait for further instructions on how/if to procceed.
var input = document.querySelector('input')
var tagify = new Tagify(input,{
hooks: {
/**
* Removes a tag
* @param {Array} tags [Array of Objects [{node:..., data:...}, {...}, ...]]
*/
beforeRemoveTag : function( tags ){
return new Promise((resolve, reject) => {
confirm("Remove " + tags[0].data.value + "?")
? resolve()
: reject()
})
}
}
})
Name | Parameters | Info
---------------------- | ------------------------------------------- | --------------------------------------------------------------------------
beforeRemoveTag | Array (of Objects) | Example
suggestionClick | Object (click event data) | Example
beforePaste | tagify
, pastedText
, clipboardData
| Before pasted text was added to Tagify. Resolve with new paste value if needed
Settings
Name | Type | Default | Info
------------------------- | ---------------------------- | ------------------------------------------- | --------------------------------------------------------------------------
tagTextProp | String | "value"
| Tag data Object property which will be displayed as the tag's text. Remember to keep "value" property unique. See Also: dropdown.mapValueTo
, dropdown.searchKeys
placeholder | String | | Placeholder text. If this attribute is set on an input/textarea element it will override this setting
delimiters | String | ","
| [RegEx string] split tags by any of these delimiters. Example delimeters: ",|.| " (comma, dot or whitespace)
pattern | String/RegEx | null | Validate input by RegEx pattern (can also be applied on the input itself as an attribute) Ex: /[1-9]/
mode | String | null | Use select
for single-value dropdown-like select box. See mix
as value to allow mixed-content. The 'pattern' setting must be set to some character.
mixTagsInterpolator | Array | ['[[', ']]']
| Interpolation for mix mode. Everything between these will become a tag
mixTagsAllowedAfter | RegEx | /,\|\.\|\:\|\s/
| Define conditions in which typed mix-tags content is allowing a tag to be created after.
duplicates | Boolean | false | Should duplicate tags be allowed or not
trim | Boolean | true | If true
trim the tag's value (remove before/after whitespaces)
enforceWhitelist | Boolean | false | Should ONLY use tags allowed in whitelist.In mix-mode
, setting it to false
will not allow creating new tags.
userInput | Boolean | true | Disable manually typing/pasting/editing tags (tags may only be added from the whitelist). Can also use the disabled
attribute on the original input element.
autoComplete.enabled | Boolean | true | Tries to suggest the input's value while typing (match from whitelist) by adding the rest of term as grayed-out text
autoComplete.rightKey | Boolean | false | If true
, when →
is pressed, use the suggested value to create a tag, else just auto-completes the input. In mixed-mode this is ignored and treated as "true"
whitelist | Array | [] | An array of allowed tags (Strings or Objects). When using Objects in the whitelist array a value
property is a must & should be unique. Also, the whitelist used for auto-completion when autoCompletion.enabled
is true
blacklist | Array | [] | An array of tags which aren't allowed
addTagOnBlur | Boolean | true | Automatically adds the text which was inputed as a tag when blur event happens
pasteAsTags | Boolean | true | Automatically converts pasted text into tags
callbacks | Object | {} | Exposed callbacks object to be triggered on events: 'add'
/ 'remove'
tags
maxTags | Number | Infinity | Maximum number of allowed tags. when reached, adds a class "tagify--hasMaxTags" to <Tags>
editTags | Object/Number | {} | false
or null
will disallow editing
editTags.clicks | Number | 2 | Number of clicks to enter "edit-mode": 1 for single click. Any other value is considered as double-click
editTags.keepInvalid | Boolean | true | keeps invalid edits as-is until esc
is pressed while in focus
templates | Object | wrapper
, tag
, dropdownItem
| Object consisting of functions which return template strings
validate | Function | | If the pattern
setting does not meet your needs, use this function, which recieves tag data object as an argument and should return true
if validaiton passed or false
/string
of not. A string may be returned as the reason of the validation failure.
transformTag | Function | | Takes a tag data as argument and allows mutating it before a tag is created or edited and also before validation.Should not return
anything, only mutate the argument.
keepInvalidTags | Boolean | false | If true
, do not remove tags which did not pass validation
skipInvalid | Boolean | false | If true
, do not add invalid, temporary, tags before automatically removing them
backspace | | true | On pressing backspace key: true
- remove last tag edit
- edit last tagfalse
- do nothing (useful for outside style)
originalInputValueFormat | Function | | If you wish your original input/textarea value
property format to other than the default (which I recommend keeping) you may use this and make sure it returns a string.
mixMode.insertAfterTag | Node/String | \u00A0
| node
or string
to add after a tag added |
a11y.focusableTags | Boolean | false | allows tags to get focus, and also to be deleted via Backspace
dropdown.enabled | Number | 2 | Minimum characters input for showing a suggestions list. false
will not render a suggestions list.
dropdown.caseSensitive | Boolean | false | if true
, match exact item when a suggestion is selected (from the dropdown) and also more strict matching for dulpicate items. Ensure fuzzySearch
is false
for this to work.
dropdown.maxItems | Number | 10 | Maximum items to show in the suggestions list
dropdown.classname | String | ""
| Custom classname for the dropdown suggestions list
dropdown.fuzzySearch | Boolean | true | Enables filtering dropdown items values' by string containing and not only beginning
dropdown.sortby | String/Function | | If set as startsWith
string, the suggestions list will be sorted with matched items which starts with the query shown first, and exact matches shown before all. If this setting is defined as a function
, it recieves two arguments: the array of filtered items and the query and it must return an Array.(default sorting order is same as the whitelist's)
dropdown.accentedSearch | Boolean | true | Enable searching for accented items in the whitelist without typing exact match (#491)
dropdown.position | String | "all"
| manual
- will not render the dropdown, and you would need to do it yourself. See demotext
- places the dropdown next to the caretinput
- places the dropdown next to the input (useful in rare situations)all
- normal, full-width design
dropdown.highlightFirst | Boolean | false | When a suggestions list is shown, highlight the first item, and also suggest it in the input (The suggestion can be accepted with → key)
dropdown.closeOnSelect | Boolean | true | close the dropdown after selecting an item, if enabled:0
is set (which means always show dropdown on focus)
dropdown.clearOnSelect | Boolean | true | Keep typed text after selecting a suggestion
dropdown.mapValueTo | Function/String | | If whitelist is an Array of Objects:Ex. [{value:'foo', email:'[email protected]'},...]
) this setting controlls which data key will be printed in the dropdown. Ex.1: mapValueTo: data => "To:" + data.email
Ex.2: mapValueTo: "email"
dropdown.searchKeys | Array | ["value", "searchBy"]
| When a user types something and trying to match the whitelist items for suggestions, this setting allows matching other keys of a whitelist objects
dropdown.appendTarget | HTMLNode | document.body
| Target-Node which the suggestions dropdown is appended to (only when rendered)
dropdown.placeAbove | Boolean | | If defined, will force the placement of the dropdown in respect to the Boolean value: true
will always show the suggestions dropdown above the input field and false
will always show it below. By default this setting it not defined and the placement of the dropdown is automatically decided according to the space availble, where opening it below the input is preferred.