Giter Club home page Giter Club logo

bootstrap5-tags's Introduction

Tags for Bootstrap 4/5

NPM Downloads

How to use

An ES6 native replacement for select using standards Bootstrap 5 (and 4) styles.

(almost) No additional CSS needed! Supports creation of new tags.

import Tags from "./tags.js";
Tags.init();
// Tags.init(selector, opts);
// You can pass global settings in opts that will apply
// to all Tags instances

By default, only provided options are available. Validation error will be displayed in case of invalid tag.

<label for="tags-input" class="form-label">Tags</label>
<select class="form-select" id="tags-input" name="tags[]" multiple>
  <option disabled hidden value="">Choose a tag...</option>
  <option value="1" selected="selected">Apple</option>
  <option value="2">Banana</option>
  <option value="3">Orange</option>
</select>
<div class="invalid-feedback">Please select a valid tag.</div>

Creation of new tags

Use attribute data-allow-new to allow creation of new tags. Their default value will be equal to the text. Since you can enter arbitrary text, no validation will occur.

<select class="form-select" id="tags-input" name="tags[]" multiple data-allow-new="true"></select>

You can force these new tags to respect a given regex.

NOTE: don't forget the [] if you need multiple values!

Server side support

You can also use options provided by the server. This script expects a json response that is an array or an object with the data key containing an array.

Simply set data-server where your endpoint is located. It should provide an array of value/label objects. The suggestions will be populated upon init except if data-live-server is set, in which case, it will be populated on type. A ?query= parameter is passed along with the current value of the searchInput.

You can preselect values either by using data-selected or by marking the suggestion as selected in the json result.

<label for="validationTagsJson" class="form-label">Tags (server side)</label>
<select
  class="form-select"
  id="validationTagsJson"
  name="tags_json[]"
  multiple
  data-allow-new="true"
  data-server="demo.json"
  data-live-server="1"
>
  <option disabled hidden value="">Choose a tag...</option>
</select>

You can pass additionnal parameters with data-server-params and choose the method with data-server-method (GET or POST).

Setting data programmatically

You can use the items config key to pass options. These will be added to the select object. Items can be an array of Suggestions, or a key:value object.

You can also call setData manually.

Options

Options can be either passed to the constructor (eg: optionName) or in data-option-name format. You can also use the data-config attribute with a json encoded string.

Name Type Description
items Array.<(Suggestion|SuggestionGroup)> Source items
allowNew Boolean Allows creation of new tags
showAllSuggestions Boolean Show all suggestions even if they don't match. Disables validation.
badgeStyle String Color of the badge (color can be configured per option as well)
allowClear Boolean Show a clear icon
clearEnd Boolean Place clear icon at the end
selected Array A list of initially selected values
regex String Regex for new tags
separator Array | String A list (pipe separated) of characters that should act as separator (default is using enter key)
max Number Limit to a maximum of tags (0 = no limit)
placeholder String Provides a placeholder if none are provided as the first empty option
clearLabel String Text as clear tooltip
searchLabel String Default placeholder
showDropIcon Boolean Show dropdown icon
keepOpen Boolean Keep suggestions open after selection, clear on focus out
allowSame Boolean Allow same tags used multiple times
baseClass String Customize the class applied to badges
addOnBlur Boolean Add new tags on blur (only if allowNew is enabled)
showDisabled Boolean Show disabled tags
hideNativeValidation Boolean Hide native validation tooltips
suggestionsThreshold Number Number of chars required to show suggestions
maximumItems Number Maximum number of items to display
autoselectFirst Boolean Always select the first item
updateOnSelect Boolean Update input value on selection (doesn't play nice with autoselectFirst)
highlightTyped Boolean Highlight matched part of the suggestion
highlightClass String Class applied to the mark element
fullWidth Boolean Match the width on the input field
fixed Boolean Use fixed positioning (solve overflow issues)
fuzzy Boolean Fuzzy search
startsWith Boolean Must start with the string. Defaults to false (it matches any position).
singleBadge Boolean Show badge for single elements
activeClasses Array By default: ["bg-primary", "text-white"]
labelField String Key for the label
valueField String Key for the value
searchFields Array Key for the search
queryParam String Name of the param passed to endpoint (query by default)
server String Endpoint for data provider
serverMethod String HTTP request method for data provider, default is GET
serverParams String | Object Parameters to pass along to the server. You can specify a "related" key with the id of a related field.
serverDataKey String By default: data
fetchOptions Object Any other fetch options (https://developer.mozilla.org/en-US/docs/Web/API/fetch#syntax)
liveServer Boolean Should the endpoint be called each time on input
noCache Boolean Prevent caching by appending a timestamp
allowHtml Boolean Allow html in input (can lead to script injection)
inputFilter function Function to filter input
sanitizer function Alternative function to sanitize content
debounceTime Number Debounce time for live server
notFoundMessage String Display a no suggestions found message. Leave empty to disable
onRenderItem RenderCallback Callback function that returns the suggestion
onSelectItem ItemCallback Callback function to call on selection
onClearItem ValueCallback Callback function to call on clear
onCreateItem CreateCallback Callback function when an item is created
onBlur EventCallback Callback function on blur
onFocus EventCallback Callback function on focus
onCanAdd AddCallback Callback function to validate item. Return false to show validation message.
onServerResponse ServerCallback Callback function to process server response. Must return a Promise
onServerError ErrorCallback Callback function to process server errors.
confirmClear ModalItemCallback Allow modal confirmation of clear. Must return a Promise
confirmAdd ModalItemCallback Allow modal confirmation of add. Must return a Promise

Any of these config option can be changed later with setConfig.

To know more about these features, check the demo!

Callbacks

EventCallback ⇒ void

Param Type
event Event
inst Tags

ServerCallback ⇒ Promise

Param Type
response Response

ErrorCallback ⇒ void

Param Type
e Error
signal AbortSignal
inst Tags

ModalItemCallback ⇒ Promise

Param Type
label String
inst Tags

RenderCallback ⇒ String

Param Type
item Suggestion
label String
inst Tags

ItemCallback ⇒ void

Param Type
item Suggestion
inst Tags

ValueCallback ⇒ void

Param Type
value String
inst Tags

AddCallback ⇒ void | Boolean

Param Type
value String
data Object
inst Tags

CreateCallback ⇒ void

Param Type
option HTMLOptionElement
inst Tags

Tips

  • You can also use it on single selects! :-)
  • Use arrow down to show dropdown
  • If you have a really long list of options, a scrollbar will be used
  • Access Tags instance on a given element with Tags.getInstance(mySelect)

Style

While styling is not mandatory, some pseudo styles may help align your styles with a regular bootstrap form-control We basically replicate input state as pseudo classes on the form-control container

  • Support focus styles by implementing a pseudo class form-control-focus
  • Support improved floating labels by implementing a pseudo class form-placeholder-shown
  • Support disabled styles by implementing a pseudo class form-control-disabled

These styles can be found in _tags.scss

You can also use the tags-pure.scss file which provide you a css vars only version of the required styles (works well with bootstrap 5.3)

Without Bootstrap 5

Bootstrap 4 support

Even if it was not the initial idea to support Bootstrap 4, this component is now compatible with Bootstrap 4 because it only requires minimal changes.

Check out demo-bs4.html

Standalone usage

Obviously, this package works great with the full bootstrap library, but you can also use it without Bootstrap or with a trimmed down version of it

Actually, this library doesn't even use the js library to position the dropdown menu, so its only dependencies is on css classes. You can check out the .scss file to see how to reduce bootstrap 5 css to a smaller size.

Check out demo-standalone.html

Demo

https://codepen.io/lekoalabe/pen/ExWYEqx

How does it look ?

screenshot

Do you need to init this automagically ?

You can now use this as a custom element as part of my Formidable Elements collection.

Or you can use Modular Behaviour (see demo)

Browser supports

Modern browsers (edge, chrome, firefox, safari... not IE11). Add a warning if necessary.

Also check out

How to contribute

If you want to make a PR, please make your changes in tags.js and do not commit any build files They will be updated upon release of a new version.

If you want to test your changes, simply run npm start and test in demo.html (feel free to add new test cases).

For scss updates, apply changes to scss files. They need to be compiled manually since they are not meant to be used by themselves.

bootstrap5-tags's People

Contributors

dazzar56 avatar edika99 avatar fahmij8 avatar gaetanbrl avatar hellehata avatar hoytron avatar kuboon avatar lekoala avatar mariusa avatar un0tec avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

bootstrap5-tags's Issues

[Issue] Tags fail to calculate the input size if the original list is empty

When working with an empty select list to let the user enter as many tags as they wish, Tags will fail to properly calculate the input size and will throw an error in the console as follows:

Uncaught TypeError: Cannot read properties of undefined (reading 'length') at Tags.#adjustWidth (app.js:...) at Tags.#configureSearchInput (app.js:...) at new Tags (app.js:...) at Function.init (app.js:...) at HTMLDocument.<anonymous> (app.js:...)

Validation Regex

What is the correct way to use the regex validation? I think I've tried every possible option and nothing seems to do what I want. It either has no effect, or it prevents all entries.

Using this code:
select_el.setAttribute("data-regex", /[A-z]/);

I have confirmed through the Tags class using console.log("REGEX: " + this.validationRegex); that my regex value is being passed into the Tags class, but as stated above, the outcome not right.

I have tried it with/without quotes, with/without "gi", with/without brackets, and probably other ways too. I'm out of ideas.

Thanks for your help.

Different style and/or color for each tag

Congratulations for this snippet.
I wonder if it can be posible to have different color and/or style per tag.
May be with an attribute in each <option>. For example:
<option value="1" data-badge-style="secondary">First</option>
<option value="2" data-badge-style="primary">Second</option>

Thank you for your work !!

Pressing enter after tag was added adds the tag again

If you add a predefined tag from the list, and press enter again, that tag will also get added again. This doesn't happen when you add a new tag.

Video below was recorded on the Codepen demo in "Tags new" input, but the same happens in the "Tags" input. First I added "Banana" tag which os one of the predefined tags and then pressed enter few times. The tag was also added multiple times. Then I refreshed the page and added "Test" tag which is a new tag and again pressed enter multiple times, but tag was not added.

adding.tag.mp4

Is it possible to prevent adding the same tag multiple times this way?

Backspace not working?

Not sure if this was implemented (although I saw some issue related to this), but can we clear tags by using backspace on the keyboard? I tried it, but it doesn't delete tags when trying to do that.

Tested on Edge/Chrome ...

Dropdown doesn't render when only 1 result is returned from live server source

Hi,

I'm trying to use Tags as a user-friendly field for identifying a particular, single database record.

A simple example might be a private messaging system, which searches a database of usernames. If multiple results are returned, the dropdown menu with all valid suggestions renders correctly, but if only one is found it doesn't render at all - no .show is generated - and the containing .form-control.dropdown gets .is-invalid added.

<select multiple name="person" data-placeholder="Start typing"
                        id="suggestfield"
                        data-server="/user-suggest/"
                        data-live-server="1"
                        data-suggestions-threshold="3"
                        data-allow-clear="1"
                        data-full-width="1"
                        data-max="1">
                        <option disabled hidden value="">Choose a person</option>
                    </select>
import Tags from "/js/tags.js";
Tags.init("#suggestfield");

I've simplified a few values for explanation, but that is otherwise my code. Correctly formed JSON is returned, and no errors are reported in console; it simply seems to be not liking having only one single possible suggestion. I've updated whatever I may have been using to 1.4.34 with no change.

Post-thought: Could it be that the queried string is not necessarily within the returned suggestion text, as I am also searching an AKA table, but only returning the root text value?

Styling Functionality

Marvelous plugin. I see there's a way to add a custom class, however one cannot add multiple classes.

IE:
data-badge-class="text-dark someOtherClass"

Will throw an error: Failed to execute 'add' on 'DOMTokenList': The token provided ('text-dark someOtherClass') contains HTML space characters, which are not valid in tokens.

Could a split of some form be added for when multiple classes would be useful?

Further, is it possible to style the dropdown suggestions with the same class?

Keeping form inputs after sending

Hi and thanks again for this awesome plugin.
I'm trying to keep the inputs a user makes in the tags input field after sending the form. For simple text input fields, adding
value="{{ request.form['id of the field'] }}"
keeps the values after input. Is there a way to achieve something similar fot the tags inputs? Would have to be applicable to newly added tags.
Thanks a lot!

Missing server side features

Hy, I spent part of my day implementing this library. It's really nice to use. But for me it's missing an important element: we can't initialize the input field with selected value (with JSON or with init function).

It's really a pity !

This issue is just an idea for improvement, if you want to implement it I am available to test. Otherwise you can close it.

Have a nice day !

[Bug] Removed tags cannot be readded

When a user adds a tag, then backspaces or clicks a button to remove it then the tag disappears from the list and cannot be readded.

P.S. This project has been an absolute life saver for my project. Thank you!

Unexpected popup selection when the init data over max

This is the code :

<select class="form-control" id="tags" name="tags" multiple data-allow-clear="true" data-suggestions-threshold="0" data-max="2">
    <option selected disabled hidden value="">Choose</option>
    <option value="1" selected="selected" data-init="1">111</option>
    <option value="2" selected="selected" data-init="1">222</option>
    <option value="3" selected="selected"  data-init="1">333</option>
    <option value="4" data-init="1">444</option>
    <option value="5" data-init="1">555</option>
</select>

Thanks.

[Enhancement] Allow to programmatially clear all selected values

I'm trying to find a way to programmatically clear all selections and display the placeholder back. Not just like a reset to default values since there will be cases where selected values are not valid anymore.

I see a removeActiveSelection method but that didn't do the trick for me, there's also a removeAll method but it seems a little extreme for this use case.

Enter and backspace key not detected in mobile

First off all, amazing work dude!
But, I encounter some problem using this library which is as it says in the title. Luckily I know the way around that. Which is to use event.keyCode rather than event.code on input keydown event and it works. I would love to make a pull request but I would like to hear some feedback first, Cheers🍺.

Form returning only first value/tag to python

Hi, thanks so much for this simple yet awesome feature. I have one small issue when using it. I want to use it solely for entering "new" tags, so without a "lookup" functionality, within a form in html. I want to pass the data entered to python back-end. However, python only receives the very first value/tag as opposed to the whole list of tags entered. Any idea what may be causing this?
Thanks in advance!
Stefan

[Issue] No need to keep the selection popup open if max = 1

On a recent enhancement request it was asked to keep the selection popup open when the multiple attribute is present on a select element. I found a small glitch on how the code was implemented: if multiple attribute is set but only one selection possible (max option set to 1) there's no need to keep displaying the popup since only one selection possible and it was already selected.

To replicate:

  1. Set the multiple attribute on a select element.
  2. Set the max option to 1, wither by data attributes or global options.
  3. Load the website and select one option from the affected element.
  4. The selection popup remains open but only one option is allowed.

A side effect issue of this, is that if you switch options from this dropdown a couple times, the popup will remain open no matter what, even if another popup is triggered from a different element.

[Issue] Disabled options on the original select element are visible/selectable on Tags UI

When the original select element has one or more disabled options, after the Tags UI gets populated items matching the originally disabled options will be still visible and selectable thus leading to potential validation issues.

Users should not be able to select an option that is disabled, Tags should provide a way to either disable or hide options as needed.

Dropdown overlaps validation error

Dropdown with data-suggestions overlaps error message(class="invalid-feedback") below the select field.
Dropdown should be hidden immediately once validation error occurs.
And validation error message should not disappear after focus is moved away from the select field with error.

image

#bootstrap5

[Enhancement] Max number of tags

I'd like the capability to specify the maximum number of tags supported by the multiple select.
Maybe something like a new attribute data-max-tags.
For instance, if

  • available options are: apple, banana, and orange
  • data-max-tags="2"
  • currently selected options are banana and orange

then the user can't add apple unless he/she removes something first.

This feature would be useful, for instance, when selected options are saved as colums in a relational db, especially if data-allow-new="true"

@lekoala What do you think?

[Enhancement] Query server response as the user types in

Currently, there's only an all or nothing way to retrieve resources from the server, which in turn can be counter productive when retrieving lots of data. Will be nice to have feature to allow to query server as the user types in so that data is returned in small chunks.

Cannot insert new tag if the new tag is substring of other tags

From demo.html, there are 3 options, "Apple", "Banana", "Orange".
If I would like to insert a new tag called "an", it will highlight "Banana" in suggestions as shown below. Pressing enter would choose "Banana" but not the new tag "an".
image

Is it possible for users to press escape to hide the menu? Or not selecting any options by default?

I do not know JavaScript well, but i have tried adding few lines of codes and it worked for me:

// Other key handlers
// After line 364
case 27:
case "Escape":
  this.#hideSuggestions();
  break;

Issue with click on dropdown item

Just noticed that if you click on an item of the dropdown and don't release the mouse button immediatly (literally) the dropdown close without adding the tag. You have to click very fast to make it work; which is a bit annoying.
You can easily reproduce the issue on the online demo.
It happens in my code too.

[Issue] data-separator is not working on Chrome for Android

As weird as it seems, data-separator is not working on Chrome for Android: the only tags that will be selected are the ones picked from the dropdown, so you are not allowed to enter tags on the fly. This is working perfectly fine on Chrome desktop.

[Issue] Change event fired from Tags does not bubble up to document root

It's common practice, at least for me, to listen to event updates directly on the document selector rather than on each individual element dispatching. This allow me to sort of of standard way to listen for event for both static and dynamically loaded DOM elements. The issue with tags is that the event is not bubbling up all the way up to the document element so I am not able to capture the change event without major refactoring of my code. I have created a Jsfiddle illustrating my point, see below:

https://jsfiddle.net/unckv93h/

See that nothing is logged to console when adding the event listener right into the document selector.

Deselect First Element

The first option is deselected after the init process, is there any misconfiguration?

The Originalcode

<select class="form-select" id="tags-input" name="tags[]" multiple="" data-allow-new="true" data-server="pathToServer" data-live-server="1" data-allow-clear="true" data-badge-style="info">
  <option value="6" selected="selected">tree</option>
  <option value="3" selected="selected">star</option>
  <option value="2" selected="selected">adsf</option>
  <option value="1" selected="selected">asdf</option>
</select>

After the init process (and tree is not shown)

<select class="form-select" id="tags-input" name="tags[]" multiple="" data-allow-new="true" data-server="pathToServer" data-live-server="1" data-allow-clear="true" data-badge-style="info" style="display: none;">
  <option value="6">tree</option>
  <option value="3" selected="selected" data-init="1">star</option>
  <option value="2" selected="selected" data-init="1">adsf</option>
  <option value="1" selected="selected" data-init="1">asdf</option>
</select>

How can I keep the select form I want?

I am using the following form.
<div class="col-sm-3"><select class="" id="exampleGroup5"><option value="두피" data-init="1" selected="selected">두피</option><option value="스킨">스킨</option><option value="페이셜">페이셜</option></select></div><div class="col-sm-3"><select class="form-select" id="separatorTags" name="tags_separator[]" multiple data-allow-new="true" data-allow-clear="true" data-separator=" |,| "><option value="">Type a tag...</option><!-- you need at least one option with the placeholder --></div>

The problem with this is that the part I want to use in the "select" form is also changed to the "tags input" form.
How can I keep the select form I want?

[Issue] suggestionsThreshold is not applied when set in Global options

I am setting some global options up when initializing the Tags object, but the expected results per the applied settings are not taking place. Only way settings are applied is when using data attributes.

For example:

Tags.init(tagsSelector, { allowClear: true, suggestionsThreshold: 0, });

doesn't work. So I need to explicitly set the data attributes on the element by either altering HTML code or tricking Tags before initializing by programmatically adding the attributes. Like this...
document.querySelectorAll(tagsSelector).forEach(tagsEl => { tagsEl.dataset.allowClear = true; tagsEl.dataset.suggestionsThreshold = 0; });

The expected result is that when initializing Tags with an options object, specified settings take effect on the UI as expected.

[Issue] Single select with a placeholder still defaults to first option

When you declare an empty option to use as a placeholder on a single select element, even tho the placeholder is displayed properly, if you try to get the value of the element you will confirm that it's taking the value from the first not empty option.

On a similar note, and I believe this is new to this version, a single select with no placeholder doesn't display the first available option as expected.

JSFiddle ahead... https://jsfiddle.net/xkr5uyLe/

[enhancement] Option to keep the results list open while selecting values

When querying server-side, one might want to select multiple values from results. Now one has to type the same query again after selecting a value.

An option to keep the list of results open while selecting values (until clicking outside of the list) would be useful.

This also needs to keep existing search value after selecting items.

eg https://vue-multiselect.js.org/#sub-select-with-search

 :close-on-select="false",
 :clear-on-select="false",

improve suggestions drop-down position

The current suggestions drop-down position is right under letters entered by user.
There are some issues with this:

  1. using keepOpen, the drop-down list position changes/jumps on screen after each selection.
  2. when entering text towards the end of input, the dropdown goes out of screen:
    2022-03-17_15-30

Suggested fix: keep drop-down in a fixed position, always under the input, similar to https://vue-multiselect.js.org/
This would solve both issues.
2022-03-17_15-36

Getting live results from server

I am attempting to get the live tag suggestions from my database. I think I have it almost working... Using the debugger, I have found that results are being returned to the browser in JSON format, but the web page still doesn't show any drop down with suggestions.

The "read me" page doesn't give details on the expected structure of the JSON results coming from a server. The structure I have chosen was just a wild guess so it is most likely the problem.

The structure looks like this: {"3":"work","4":"home"}

Or generally speaking, this format: {database_id: tag_name, database_id: tag_name}

Is that structure the problem?

Also, is there a more detailed instructional page that goes into more detail than the github read me page?

Thanks for your help!

[Issue] If original select is disabled by default the popup selection is never triggered after resetState()

When the original select is disabled when DOM is loaded, the Tags popup selection is never triggered after resetState() method is called.

Check the JSFiddle example below so you can confirm.

https://jsfiddle.net/1xpqo94k/

PD: another issue that I believe shares the same root cause is that after disabling a select that was not originally disabled and then calling resetState(), the field looks as it is disabled (visually at least), but the popup selection is still triggered when threshold is 0.

Demo error

Please, check your demo page - the package functionality is displayed incorrectly there

[enhancement] Server side: support custom column names

Hi,

Server side should provide an array of value/label objects.

Would it be possible to please have new constructor options which say what server-side fields map to value/label?
eg valueField: 'id', labelField: 'title'

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.