Do you like this project? Please support my Mecha CMS project too. Thank you!

Tag Picker 4.1.0

Tag Picker is a JavaScript application designed to simplify the management of comma-separated lists of words, offering a minimalist interface for an enhanced user experience. Users can easily add tags by typing a word and pressing the , key (by default), or remove tags with a quick click (or by using common keys such as the Backspace or Delete keys). Developers can easily integrate and customize this application styles to match the design of their web project.

It supports native keyboard interaction as if it were plain text. You should be able to copy, cut, and paste from/to the mask. Click a tag to select it, press the Control key while clicking the tag to select multiple tags. You can also select the tags using the combination of Shift and ArrowLeft or ArrowRight keys.

# 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

# Tweaks

# Constructor

const picker = new TagPicker(self, join = ', ');
const picker = new TagPicker(self, state = {
    escape: [','],
    join: ', ',
    max: Infinity,
    min: 0,
    pattern: null,
    with: []
});

# 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.

state.join

The character to join the tags (usually a comma followed by a space).

state.max

The maximum number of tags that can be inserted.

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.

state.pattern

If defined, tag insertion will be performed only if tag name is matched with the pattern.

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()

Disables the application methods (except for the attach() method) 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._event]);

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.get(name)

Returns the tag position in the list, starting from 0.

if (null !== picker.get('foo')) { … }

picker.let(name)

Removes a tag by its name.

picker.let('foo'); // Remove “foo” tag
picker.let(); // Reset to the initial value

picker.off(event, then)

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, then)

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);

picker.set(name, at = -1)

picker.set([name, title ?? name], at = -1)

Adds a new tag with the given name.

picker.set('foo'); // Append “foo” tag
picker.set('bar', 0); // Prepend “bar” tag
picker.set('baz', 2); // Insert “baz” tag at index 2 in the list
picker.set(['cry', '😭']); // Append “cry” tag displayed as “😭”

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.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.self

Returns the <input> element.

console.log(picker.self.getAttribute('name'));

picker.state

Returns the application states if any.

console.log(picker.state);

picker.text

Gets or sets the current text in the tag picker’s input.

console.log(picker.text);
picker.text = 'foo, bar, baz';

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 = 'foo, bar, baz';

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'), {
    foo: ['bar', 'baz', 'qux']
});

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.a = 1;
    this.b = function () {};
    return this;
}

Object.defineProperty(Extension, 'name', {
    value: 'Extension'
});

Extension as an object:

const Extension = {
    attach: function (self, state = {}) {},
    detach: function (self, state = {}) {},
    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

Use it for free, pay if you get paid. So, you’ve just benefited financially after using this project? It’s a good idea to share a little financial support with this open source project too. Your support will motivate me to do any further development, as well as to provide voluntary support to overcome problems related to this project.

Thank you! ❤️