# Usage
Note: CSS variables have been removed since version 4.0.0. From now on, I will only provide a minimal style just to make viable interaction. Expect it to look ugly by default. The main goal of this application is to be able to integrate it seamlessly into your web design. By providing a minimal style, it is easy to add other styles to it to adapt it to your own web design. Have a look at the source code on this page to see how I adapted the style to resemble the default style of the previous version.
# Browser
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="utf-8">
<link href="./index.min.css" rel="stylesheet">
<style>
.tag-picker {
width: 100%;
}
</style>
</head>
<body>
<p>
<input type="text">
</p>
<script src="./index.min.js"></script>
<script>
const picker = new TagPicker(document.querySelector('input'));
</script>
</body>
</html>
# Node.js
Functions and methods in this application are mostly native JavaScript and are intended for use by the browser. Node.js doesn’t know about the DOM, so this kind of practice will probably be used more often to build new browser packages than to be used directly in the Node.js server.
# CommonJS
const TagPicker = require('@taufik-nurrohman/tag-picker').default;
const picker = new TagPicker(document.querySelector('input'));
# ECMAScript
import TagPicker from '@taufik-nurrohman/tag-picker';
const picker = new TagPicker(document.querySelector('input'));
# Tests
- No Idea?
- Attach, Detach
- Convert Tag Name
- Copy, Cut, and Paste Events
- Custom Tags Separator
- Disabled Characters
- Disabled State
- Focus Automatically
- Form Events
- Invalid State
- Limit Maximum Tags
- Limit Minimum Tags
- Read-Only State
- Required State
- Validate Tag Name
# Tweaks
- Converted Tag Display
- Hide Input Hint on Focus
- Insert Tag Name on Blur
- Tags as Array
- Warn for Duplicate Tags with Alert Message
- Warn for Duplicate Tags with Description Below the Input
- Warn for Duplicate Tags with Flash Highlight
# Constructors
# TagPicker(self, state)
const picker = new TagPicker(self, join = ', ');
const picker = new TagPicker(self, state = {
escape: [','],
join: ', ',
max: Infinity,
min: 0,
pattern: null,
time: {
error: 1000
}
with: []
});
# TagPicker.Tags(picker, tags)
This constructor is used internally. It is the return value of the picker.tags
property. It contains methods like get()
, has()
, let()
, and set()
to modify the current tags.
const tags = new TagPicker.Tags(picker, ['Tag 1', 'Tag 2', 'Tag 3']);
# Parameters
# self
The <input>
element.
# join
The character to join the tags (usually a comma followed by a space).
# state
The configuration data.
# state.escape
List of characters to trigger the tag insertion. It is [',']
by default, which means that you cannot have a ','
character in the tag name. You can also add '\n'
and '\t'
to the list so that it will insert a tag when you press the Tab or Enter key.
const picker = new TagPicker(document.querySelector('input'), {
escape: [',', ' ', '\n', '\t']
});
# state.join
The character to join the tags (usually a comma followed by a space).
const picker = new TagPicker(document.querySelector('input'), '+');
const picker = new TagPicker(document.querySelector('input'), {
join: '+'
});
# state.max
The maximum number of tags that can be inserted.
const picker = new TagPicker(document.querySelector('input'), {
max: 25
});
# state.min
The minimum number of tags that must be inserted to be able to submit the form. The default value of this state is set to 0
, but if the required
attribute is present on the <input>
element, then the default value of this state will be set to 1
.
const picker = new TagPicker(document.querySelector('input'), {
min: 5
});
# state.pattern
If defined, the tag will be inserted only if the input matches the pattern. if value is defined as a function, this configuration will be used to convert the current input to the desired tag format. return value can be a string or an array containing the desired tag text and its attributes.
const picker = new TagPicker(document.querySelector('input'), {
pattern: '^[a-z\\d]+(-[a-z\\d]+)*$'
});
picker.on('is.tag', name => {
console.info('The input “' + name + '” is a valid tag name.');
});
picker.on('not.tag', name => {
console.error('The input “' + name + '” is not a valid tag name.');
});
const picker = new TagPicker(document.querySelector('input'), {
pattern: function (value) {
return (value || "").toLowerCase().replace(/[^a-z\d-]/gi, '-').replace(/-+/g, '-').replace(/^-|-$/g, "");
}
});
const picker = new TagPicker(document.querySelector('input'), {
pattern: function (value) {
return [value, {
value: (value || "").toLowerCase().replace(/[^a-z\d-]/gi, '-').replace(/-+/g, '-').replace(/^-|-$/g, "")
}];
}
});
# state.time
Stores configuration data related to time in milliseconds.
# state.time.error
Determines how long the invalid state is presented to the user. If the value is less than or equal to 0
, the built-in invalid state will be disabled.
const picker = new TagPicker(document.querySelector('input'), {
time: {
error: 999999999 // As long as possible
}
});
const picker = new TagPicker(document.querySelector('input'), {
time: {
error: 0 // Disable the built-in invalid state
}
});
# state.with
List of callable functions or objects containing an attach()
method to be invoked each time the application is initialized. A very simple “plugin” system.
# Methods
# Instance Methods
Instance methods are methods available through the results of a TagPicker
construct.
# picker.attach(self, state)
Re-initializes the application and its extensions after it has been detached.
picker.attach();
# picker.blur()
Blurs from the tag picker’s input.
picker.blur();
# picker.detach()
Removes the application view and executes the detach()
method of the extensions, if they are present.
picker.detach();
# picker.fire(event, data, that)
Fires an event.
picker.fire('change', [picker.value]);
# picker.focus(mode = true)
Focuses to the tag picker’s input. If it has a text, it will select the text as well.
picker.focus(); // Focus and select the text
picker.focus(-1); // Focus and put the caret to the start of the text
picker.focus(+1); // Focus and put the caret to the end of the text
# picker.off(event, task)
Removes an event.
picker.off('change'); // Remove all events from the `change` event container
picker.off('change', onChange); // Remove `onChange` event from the `change` event container
# picker.on(event, task)
Adds a new event.
picker.on('change', function () {
console.log(this.value.split(this.state.join));
});
function onChange() {
console.log(this.value.split(this.state.join));
}
picker.on('change', onChange);
# Static Methods
Static methods are methods available directly on the TagPicker
object.
# TagPicker.from(self, state)
Creates a new TagPicker
instance.
const picker = TagPicker.from(document.querySelector('input'));
# TagPicker.of(self)
Gets TagPicker
instance of an element.
document.querySelectorAll('input').forEach(self => {
const picker = TagPicker.of(self);
});
# Properties
# Instance Properties
Instance properties are properties available through the results of a TagPicker
construct.
# picker.active
Gets or sets the active state of the tag picker. By setting the value to false
or true
, the disabled state of the source element will also be set automatically.
picker.active = false; // Make the tag picker “disabled”
picker.active = true; // Make the tag picker “enabled”
# picker.fix
Gets or sets the read-only state of the tag picker. By setting the value to false
or true
, the read-only state of the source element will also be set automatically.
picker.fix = true; // Make the tag picker “read-only”
# picker.hooks
Returns the events data.
console.log(picker.hooks);
# picker.mask
Returns the tag picker’s mask.
picker.mask.classList.add(picker.state.n + '--dark');
# picker.max
Proxy that passes to the picker.state.max
property, with additional actions that are executed while the value is being set.
console.log(picker.max); // Returns the `picker.state.max` value
picker.max = 4; // Allow a maximum of 4 tags to be inserted.
# picker.min
Proxy that passes to the picker.state.min
property, with additional actions that are executed while the value is being set.
console.log(picker.min); // Returns the `picker.state.min` value
picker.min = 4; // Insert at least 4 tags to be able to submit the form.
# picker.self
Returns the <input>
element.
console.log(picker.self.getAttribute('name'));
# picker.state
Returns the application states if any.
console.log(picker.state);
# picker.tags
Gets the current tags list data, or sets (overwrites) the current tags list with a new data.
console.log(picker.tags);
picker.tags = [
'Tag 1',
'Tag 2',
'Tag 3'
];
// Or…
picker.tags.set('Tag 1');
picker.tags.set('Tag 2');
picker.tags.set('Tag 3');
picker.tags = [
['Tag 1', {
value: 'tag-1'
}],
['Tag 2', {
value: 'tag-2'
}],
['Tag 3', {
title: 'This is a tag description.',
value: 'tag-3'
}]
];
// Or…
picker.tags.set('tag-1', 'Tag 1');
picker.tags.set('tag-2', 'Tag 2');
picker.tags.set('tag-3', ['Tag 3', {
title: 'This is a tag description.'
}]);
picker.tags = {
'tag-1': 'Tag 1',
'tag-2': 'Tag 2',
'tag-3': 'Tag 3'
};
// Or…
picker.tags.set('tag-1', 'Tag 1');
picker.tags.set('tag-2', 'Tag 2');
picker.tags.set('tag-3', 'Tag 3');
const tags = new Map;
tags.set('tag-1', 'Tag 1');
tags.set('tag-2', 'Tag 2');
tags.set('tag-3', 'Tag 3');
picker.tags = tags;
# picker.tags.at(key)
Returns the raw tag data from its key.
console.log(picker.tags.at('tag-1'));
# picker.tags.count()
Returns the total number of tags.
console.log(picker.tags.count());
# picker.tags.get(key)
Returns the tag position in the list, starting from 0
.
if (-1 !== picker.tags.get('tag-1')) { … }
# picker.tags.has(key)
Returns true
if the tag is present.
if (picker.tags.has('tag-1')) { … }
# picker.tags.let(key)
Removes a tag by its key.
picker.tags.let('tag-1'); // Remove “tag-1” tag
picker.tags.let(); // Remove all tags
# picker.tags.set(key, value)
Adds a new tag with the given value or key and value.
picker.tags.set('tag-1');
picker.tags.set('tag-2', 'Tag 2');
picker.tags.set('tag-3', ['Tag 3', {
title: 'This is a tag description.'
}]);
# picker.text
Gets or sets the current text in the tag picker’s input.
console.log(picker.text);
picker.text = 'tag-1, tag-2, tag-3';
# picker.value
Proxy that passes to the picker.self.value
property, with additional actions that are executed while the value is being set.
console.log(picker.value);
picker.on('change', function () {
console.log(this.value);
});
picker.value = 'tag-1, tag-2, tag-3';
# picker.vital
Gets or sets the required state of the tag picker. By setting the value to false
or true
, the required state of the source element will also be set automatically. If the value is set to true
and the current picker.min
value is 0
, then it will change the current picker.min
value to 1
.
picker.vital = true; // Make the tag picker “required”
# Static Properties
Static properties are properties available directly on the TagPicker
object.
# TagPicker._
Alias for TagPicker.prototype
.
TagPicker._.clear = function () {
return (this.text = this.value = ""), this;
};
const picker = new TagPicker(document.querySelector('input'));
picker.clear(); // Clear value
# TagPicker.state
Returns the default values of picker.state
.
const picker = new TagPicker(document.querySelector('input'), {
test: [1, 2, true]
});
console.log([TagPicker.state, picker.state]);
# TagPicker.version
Returns the application version.
# Extensions
# Anatomy of an Extension
Extension as a function:
function Extension(self, state = {}) {
this.test = 1;
return this;
}
Object.defineProperty(Extension, 'name', {
value: 'Extension'
});
Extension as an object:
const Extension = {
attach: function (self, state = {}) {
this.test = 1;
return this;
},
detach: function (self, state = {}) {
delete this.test;
return this;
},
name: 'Extension'
};
# Usage of an Extension
As a core extension:
TagPicker.state.with.push(Extension);
As an optional extension:
const picker = new TagPicker(document.querySelector('input'), {
with: [Extension]
});
# List of Extensions
# License
This project is licensed under the terms of the MIT license. If this project has saved you time, please donate. Thank you! ❤️