UNPKG

bootstrap5-tags

Version:

Replace select[multiple] with nices badges for Bootstrap 5

1,107 lines (1,044 loc) 67.5 kB
<!DOCTYPE html> <html lang="en" class="no-js" data-bs-theme=""> <head> <title>Bootstrap 5 tags demo</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="color-scheme" content="light dark" /> <meta name="theme-color" content="#111111" media="(prefers-color-scheme: light)" /> <meta name="theme-color" content="#eeeeee" media="(prefers-color-scheme: dark)" /> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap" rel="stylesheet" /> <!-- jquery is NOT required but it should work with it --> <script src="https://code.jquery.com/jquery-3.7.0.min.js" integrity="sha256-2Pmvv0kuTBOenSvLm6bvfBSSHrUJ+3A7x6P5Ebd07/g=" crossorigin="anonymous"></script> <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.rtl.min.css" rel="stylesheet" /> --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" /> <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap-dark-5@1/dist/css/bootstrap-dark.min.css" rel="stylesheet" /> --> <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css" rel="stylesheet" /> --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" type="module"></script> <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js" type="module"></script> <script src="https://cdn.jsdelivr.net/npm/bs-companion@1.3.2/static/dist/bs-companion.min.js" type="module"></script> <script type="module"> import Tags from "./tags.js"; import JustValidate from "https://cdn.jsdelivr.net/npm/just-validate@4.2.0/+esm"; window.myFilter = (str) => { return str.replace(/[^a-z0-9]/gi, ''); } // callbacks can be nested window['app'] = { cityResponse: (promise, inst) => { const data = [ { "state": "Texas", "city": "Houstan" }, { "state": "Texas", "city": "San Antonio" }, { "state": "California", "city": "Los Angeles" }, { "state": "California", "city": "San Diego" } ]; if (inst.config('labelField') == "state") { const unique = []; return data.filter((el, idx) => { if (unique.indexOf(el.state) === -1) { unique.push(el.state); return true } return false; }) } return data; } } function confirmDialog(msg) { return new Promise(function (resolve, reject) { let confirmed = window.confirm(msg); return confirmed ? resolve(true) : reject(false); }); } // These need to be define before init window["customItemFormat"] = function (item, label) { return label + " (" + item.value + ")"; }; window["customOnCreate"] = function (option, inst) { console.log("new item", option.value, inst); // attach tooltip dynamically option.setAttribute('title', 'this element is created dynamically'); }; window["emailRender"] = (item, label) => { return item.data.name + " &lt;" + label + "&gt;"; }; window["emailCanAdd"] = (text, data, inst) => { const name = data.name ?? null; const vals = inst.getSelectedValues(); // Cannot email both of them if (text === "ms.x@mycompany.com" && vals.indexOf("mr.x@mycompany.com") !== -1) { toaster("Cannot email both of them"); return false; } if (text === "mr.x@mycompany.com" && vals.indexOf("ms.x@mycompany.com") !== -1) { toaster("Cannot email both of them"); return false; } return true; }; window["emailConfirmClear"] = (text, inst) => { return confirmDialog("Are you sure you want to remove " + text + " ?"); } window["emailConfirmAdd"] = (text, inst) => { return confirmDialog("Are you sure you want to add " + text + " ?"); } const validator = new JustValidate("#just_form"); validator.onSuccess((event) => { console.log("just validate", event); event.currentTarget.submit(); }); validator.onFail((fields) => { console.log("just validate", fields); }); validator.addField(document.querySelector("#just_validate"), [ { rule: "required", }, ]); validator.addField("#basic_name", [ { rule: "required", }, { rule: "minLength", value: 3, }, { rule: "maxLength", value: 15, }, ]); Tags.init("select:not(.ignore-tags)", { clearLabel: "Clear tag", allowClear: true, suggestionThresold: 0, onDataLoaded: (src) => { console.log("Loaded", src); }, onClearItem: (v) => { console.log(`Cleared ${v}`); }, onSelectItem: (item) => { console.log("selected", item); }, }); function sortSelect(elem, sort) { var tmp = []; var selectedValue = elem[elem.selectedIndex].value; for (var i = 0; i < elem.options.length; i++) { tmp.push(elem.options[i]); } tmp.sort(function (a, b) { if (sort.indexOf(a.value) === -1) { return tmp.length; } return sort.indexOf(a.value) - sort.indexOf(b.value); }); while (elem.options.length > 0) { elem.options[0] = null; } for (var i = 0; i < tmp.length; i++) { elem.options[i] = tmp[i]; } } const validationTags = document.querySelector("#validationTags"); const example1 = validationTags.parentElement.querySelector("div.form-control").querySelector("div"); new Sortable(example1, { animation: 150, filter: "input", draggable: "span", ghostClass: "blue-background-class", onEnd: function (evt) { var itemEl = evt.item; // dragged HTMLElement var oldIndex = evt.oldIndex; // element's old index within old parent var newIndex = evt.newIndex; // element's new index within new parent // Sort options according to tag orders if (oldIndex != newIndex) { const indexes = Array.from(validationTags.parentElement.querySelectorAll("span.badge")).map((badge) => { return (badge.dataset && badge.dataset.value) || -1; }); sortSelect(validationTags, indexes); } }, }); // Multiple inits should not matter Tags.init("select:not(.ignore-tags), .bs-tags"); document.addEventListener("change", (event) => { console.log(`document listener: #${event.target.id}`); }); // Reset does not fire a change input document.getElementById("regular").addEventListener("change", function (ev) { console.log(this.selectedOptions); }); // Changed is fired properly and you can getInstance if needed document.getElementById("validationTags").addEventListener("change", function (ev) { /** @type {Tags} */ let inst = Tags.getInstance(this); console.log(inst.getSelectedValues(), this.selectedOptions); }); document.getElementById("singleTags").addEventListener("change", function (ev) { console.log(this.value); }); document.querySelector(".toggle-enable").addEventListener("click", function (ev) { const el = document.getElementById("disabledTags"); el.disabled = false; // It will automatically remove the disabled attr // if (el.hasAttribute("disabled")) { // el.removeAttribute("disabled"); // } Tags.getInstance(el).resetState(); console.log("is disabled", Tags.getInstance(el).isDisabled()); }); document.querySelector(".toggle-disable").addEventListener("click", function (ev) { const el = document.getElementById("validationTags"); if (el.hasAttribute("disabled")) { el.removeAttribute("disabled"); } else { el.setAttribute("disabled", ""); } let inst = Tags.getInstance(el); inst.resetState(); }); document.querySelector(".toggle-disable2").addEventListener("click", function (ev) { const el = document.getElementById("validationTagsClear"); if (el.hasAttribute("disabled")) { el.removeAttribute("disabled"); } else { el.setAttribute("disabled", ""); } let inst = Tags.getInstance(el); inst.resetState(); }); document.querySelector(".toggle-setitem").addEventListener("click", function (ev) { const el = document.getElementById("validationTagsClear"); let inst = Tags.getInstance(el); inst.setItem(9); }); document.querySelector("#setitem3").addEventListener("click", function (ev) { const el = document.getElementById("serverSideTags"); let inst = Tags.getInstance(el); inst.setItem("server2"); }); document.querySelector("#toggle_orange_disabled").addEventListener("click", (ev) => { const el = document.getElementById("showDisabled"); let inst = Tags.getInstance(el); const orangeOption = el.querySelector("option[value='5']"); if (orangeOption.hasAttribute("disabled")) { orangeOption.removeAttribute("disabled"); toaster("Orange enabled"); } else { orangeOption.setAttribute("disabled", ""); toaster("Orange disabled"); inst.removeItem(5); // maybe you want to remove it if it was added? } inst.resetSuggestions(); // rebuild }); document.querySelector(".add-option").addEventListener("click", function (ev) { // add an option const el = document.getElementById("validationTags"); const c = el.querySelectorAll("option").length + 1; let opt = document.createElement("option"); opt.setAttribute("value", "new_" + c); opt.innerText = "Option " + c; el.appendChild(opt); console.log(el); // reset /** @type {Tags} */ let inst = Tags.getInstance(el); inst.resetSuggestions(); }); document.querySelector('.add-item').addEventListener('click', function (ev) { const el = document.getElementById("validationTags"); /** @type {Tags} */ let inst = Tags.getInstance(el); inst.addItem('test item'); }) document.querySelector(".dispose").addEventListener("click", function (ev) { const el = document.getElementById("validationTags"); /** @type {Tags} */ let inst = Tags.getInstance(el); inst.dispose(); }); document.querySelector(".clear-all").addEventListener("click", function (ev) { const el = document.getElementById("validationTags"); /** @type {Tags} */ let inst = Tags.getInstance(el); inst.removeAll(); }); document.querySelector("#darkmode").addEventListener("click", function (ev) { if (document.documentElement.dataset.bsTheme == "dark") { document.documentElement.dataset.bsTheme = "light"; } else { document.documentElement.dataset.bsTheme = "dark"; } }); document.querySelector("#makebodyscrollable").addEventListener("click", (ev) => { document.querySelector("#main").style.display = "block"; }); document.querySelector("#show_suggestions").addEventListener("click", (ev) => { ev.preventDefault(); const el = document.getElementById("inputGroupTags"); /** @type {Tags} */ let inst = Tags.getInstance(el); inst.toggleSuggestions(false); }); document.querySelector('#add_option').addEventListener("click", (ev) => { ev.preventDefault(); const input = document.getElementById('new_option'); const v = input.value; if (!v) { alert('No value'); return; } const el = document.getElementById('validationTagsNew'); const inst = Tags.getInstance(el); inst.addItem(v); }) // multiple items let items = [ { "value": 1, "label": "American" }, { "value": 2, "label": "Russian" }, { "value": 3, "label": "French" }, { "value": 4, "label": "English" }, { "group": "my group", "items": [ { "value": 5, "label": "Other 1" }, { "value": 6, "label": "Other 2" }, ] } ]; let selected = [3, 4, 5]; Tags.init("#multipleItems", { items: items, selected: selected }); let optGroupsItems = [ { "value": 1, "label": "first item" }, { "group": "my group", "items": [ { "value": "g1", "label": "Group Item 1", }, { "value": "g2", "label": "Group Item 2", }, ] }, { "group": "other group", "items": [ { "value": "o1", "label": "Other Item 1", }, { "value": "o2", "label": "Other Item 2", }, ] }, { "value": "zz", "label": "last item" }, ]; Tags.init("#optgroupsItems", { items: optGroupsItems, }); // Use native addOnBlur setting // document.querySelector('#addOnBlur').addEventListener('tags.blur', function(ev) { // // detail: {selection: 'ID', input: 'SOME_INPUT'} // const el = document.getElementById("addOnBlur"); // /** @type {Tags} */ // let inst = Tags.getInstance(el); // if(ev.detail.input && inst.canAdd(ev.detail.input)) { // inst.addItem(ev.detail.input); // inst.resetSearchInput(); // } // }); // Test dark mode (emulate in dev console => rendering => emulate) if (window.matchMedia) { const darkMode = window.matchMedia("(prefers-color-scheme: dark)").matches; if (darkMode) { console.log("Dark mode"); } else { console.log("Light mode"); } window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => { if (e.matches) { console.log("Dark mode"); } else { console.log("Light mode"); } }); } // Bootstrap 5 validation script using bs-companion FormValidator.init(); </script> <style type="text/css"> .source-sans { font-family: "Source Sans Pro", sans-serif; } .mybadge { margin-right: 0.5rem; padding: 0.25 0.5rem; font-size: 0.85rem; background: #333; } .my.test { background: palegoldenrod; } #main { width: 120vw; height: 20px; background: #eee; } /* build this with sass instead, see _tags.scss */ .form-control-focus, .form-control:focus { color: var(--bs-body-color, #212529); background-color: var(--bs-form-control-bg, var(--bs-body-bg, #fff)); border-color: rgba(var(--bs-primary-rgb, 13, 110, 253), 0.5); outline: 0; box-shadow: 0 0 0 var(--bs-focus-ring-width) rgba(var(--bs-primary-rgb, 13, 110, 253), 0.25); } .was-validated :valid+.form-control-focus, .was-validated :valid+.form-control:focus { border-color: var(--bs-success, #198754); box-shadow: 0 0 0 var(--bs-focus-ring-width) rgba(var(--bs-success-rgb, 25, 135, 84), 0.25); } .was-validated :invalid+.form-control-focus, .was-validated :invalid+.form-control:focus { border-color: var(--bs-danger, #dc3545); box-shadow: 0 0 0 var(--bs-focus-ring-width, 0.25rem) rgba(var(--bs-danger-rgb, 220, 53, 69), 0.25); } .form-floating .form-control.form-placeholder-shown:not(.form-control-focus)~label { opacity: unset; transform: unset; } .form-floating .form-control~label { z-index: unset; } .form-control-disabled { background-color: var(--bs-form-control-disabled-bg, var(--bs-secondary-bg, #e9ecef)); opacity: 1; } .tags-menu mark { text-decoration: underline; background: none; color: currentColor; padding: 0; } .form-control.is-max-reached { background-image: none; } </style> </head> <body> <div id="main" style="display: none"></div> <div class="container"> <h1>Demo</h1> <button id="darkmode">Toggle dark mode</button> <form class="needs-validation" novalidate method="get" action="https://vercel-dumper.vercel.app/"> <div class="py-3"> <input type="reset" value="Reset" class="btn btn-outline-dark" /> click reset to see values restored to their original state (including same values) </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="validationTags" class="form-label">Tags (check console to see selected values). It's sortable thanks to SortableJS (in demo, it breaks text selection) !</label> <div class="position-relative has-validation"> <select class="form-select" id="validationTags" name="tags[]" multiple data-allow-clear="dsfds" data-allow-html="1" required> <option selected="selected" disabled hidden value="">Choose a tag...</option> <option value="1" selected="selected">Apple</option> <option value="2" selected="selected">Banana</option> <option value="2" selected="selected">Banana</option> <option value="2">Banana again</option> <!-- use allow same because of identical values --> <option value="3">Orange</option> <option value="4" disabled="disabled">Disabled</option> <option value="5">This is a tag that should not overflow out of the window</option> <option value="6">abc&lt;i&gt;efg&lt;/i&gt;</option> </select> <div class="invalid-tooltip">Please select a valid tag.</div> </div> </div> <div class="col-md-4"> <button type="button" class="add-option">Add option</button> <button type="button" class="add-item">Add item</button> <button type="button" class="toggle-disable">Enable/disable</button> <button type="button" class="dispose">Dispose</button> <button type="button" class="clear-all">Clear all</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="validationTagsClear" class="form-label">Tags (allow clear + optgroup + tooltips + fuzzy)</label> <select class="form-select" id="validationTagsClear" name="tagsClear[]" multiple data-allow-clear="true" data-fuzzy="true" required> <option disabled hidden value="">Choose a tag...</option> <optgroup label="fruits"> <option value="1" selected="selected" title="my tooltip">Apple</option> <option value="2" title="my tooltip for banana">Banana</option> <option value="2" title="my tooltip for banana">Banana</option> <option value="2" title="my tooltip for banana">Banana 2 same value</option> <option value="3" title="my tooltip">Orange</option> </optgroup> <optgroup label="vegetables"> <option value="4" title="my tooltip for disabled item" disabled>Broccoli</option> <option value="5" title="my tooltip">Lettuce</option> <option value="6" title="my tooltip">Onions</option> </optgroup> <optgroup label="berries"> <option value="7" title="my tooltip">Raspberry</option> <option value="8" title="my tooltip">Cranberry</option> <option value="9" title="my tooltip">Blackberry</option> </optgroup> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div class="col-md-4"> <button type="button" class="toggle-disable2">Enable/disable</button> <button type="button" class="toggle-setitem">Set item</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="showDisabled" class="form-label">Tags (show disabled + allow html)</label> <select class="form-select" id="showDisabled" name="showDisabled[]" multiple data-allow-clear="true" data-show-disabled="true" data-allow-html="1"> <option disabled hidden value="">Choose a tag...</option> <option value="1" selected="selected">Apple</option> <option value="2">Banana</option> <option value="3" disabled selected="selected">Banana (disabled)</option> <option value="4">Orange</option> <option value="5" disabled>Orange (disabled)</option> <option value="6" selected="selected">abc&lt;i&gt;efg&lt;/i&gt;</option> <option value="7" selected="selected">a very long item that can be truncated</option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div class="col-md-4"> <button id="toggle_orange_disabled" type="button">Toggle orange disabled</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="validationTagsThreshold" class="form-label">Tags (allow clear + 1 threshold + custom active classes)</label> <select class="form-select" id="validationTagsThreshold" name="tagsClearThreshold[]" multiple data-allow-clear="true" data-active-classes="my,test,classes" data-suggestions-threshold="1"> <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> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="validationTagsShow" class="form-label">Tags (show all + custom colors)</label> <select class="form-select" id="validationTagsShow" name="tags_show[]" multiple data-show-all-suggestions="true"> <option disabled hidden value="">Choose a tag...</option> <option value="1" selected="selected">Apple</option> <option value="2" data-badge-style="success" selected="selected">Banana</option> <option value="3" data-badge-style="warning" data-badge-class="text-dark another-class">Orange</option> <option value="4" data-badge-style="secondary">Blueberry with a very long label that pushes the menu</option> <option value="5">Strawberry</option> <option value="6">Cranberry</option> <option value="7">Huckleberry</option> <option value="8">Chokeberry</option> <option value="9">Elderberry</option> <option value="10">Gooseberry</option> <option value="11">Blackberry</option> <option value="12">Raspberry</option> <option value="13">Goji berry</option> <option value="14">Salmon berry</option> <option value="15"> Sumac berry that doesn't even fit on a mobile screen because this labe is not reasonable and should be limited </option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div class="col-md-4"> You can also try with non ascii chars: <br /> <code>ㅂㅈㄷㄱㅅㅁㄴㅇㄹㅎㅋㅌㅊ</code> </div> </div> <!-- you can change color with css variables ! --> <div class="row mb-3 g-3" style="--bs-primary-rgb: 25, 135, 84"> <div class="col-md-4"> <label for="validationTagsNew" class="form-label">Tags (allow new + green primary color + starts with + filter)</label> <select class="form-select" id="validationTagsNew" name="tags_new[]" multiple data-allow-new="true" data-starts-with="true" data-input-filter="myFilter" data-not-found-message="Type the start of the string"> <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> </div> <div class="col-md-4"> <input type="text" id="new_option"> <button id="add_option">add option</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="itemsInput" class="form-label">Passing items in config</label> <select class="form-select bs-tags" id="itemsInput" data-allow-new="true" data-config='{"items": [{"value":1, "label": "Value 1", "selected": true}, {"value":2, "label": "Value 2", "disabled": true}]}'> </select> </div> <div class="col-md-4"> <label for="multipleItems" class="form-label">Multiple items</label> <select class="form-select ignore-tags" id="multipleItems" name="tags[]" multiple> <option selected disabled hidden value="">Choose a tag...</option> </select> </div> <div class="col-md-4"> <label for="optgroupsItems" class="form-label">Optgroups items</label> <select class="form-select ignore-tags" id="optgroupsItems" name="tags[]" multiple> <option selected disabled hidden value="">Choose a tag...</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="itemsInputObj" class="form-label">Passing items + object as items</label> <select type="text" class="form-control bs-tags" id="itemsInputObj" data-allow-new="true" data-config='{"items": {"1": "v1", "2": "v2"}, "selected": "1"}'></select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="validationTagsNewSame" class="form-label">Tags (allow new + same)</label> <select class="form-select" id="validationTagsNewSame" name="tags_new[]" multiple data-allow-new="true" data-allow-same="true"> <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> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="regexTags" class="form-label">Tags (allow new only if it matches regex) + confirm</label> <select class="form-select" id="regexTags" name="tags_regex[]" multiple data-allow-new="true" data-regex=".*@mycompany\.com$" data-on-render-item="emailRender" data-on-can-add="emailCanAdd" data-confirm-add="emailConfirmAdd" data-confirm-clear="emailConfirmClear" data-separator="|,|"> <option disabled hidden value="">Add mail address</option> <option value="info@mycompany.com" data-name="info" selected="selected">info@mycompany.com</option> <option value="mr.x@mycompany.com" data-name="Mr. X">mr.x@mycompany.com</option> <option value="ms.x@mycompany.com" data-name="Ms. X">ms.x@mycompany.com</option> <option value="some_value" data-name="no name">Some invalid yet callable input</option> </select> <div class="invalid-feedback">Please select only @mycompany.com addresses.</div> </div> <div class="col-md-4"> <label for="regexTagsNoNew" class="form-label">Tags (matches regex, don't allow new)</label> <select class="form-select" id="regexTagsNoNew" name="tags_regex_no_new[]" multiple data-regex=".*@mycompany\.com$"> <option disabled hidden value="">Add mail address</option> <option value="1" selected="selected">info@mycompany.com</option> <option value="2">mr.x@mycompany.com</option> <option value="3">ms.x@mycompany.com</option> </select> <div class="invalid-feedback">Please select only @mycompany.com addresses.</div> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="separatorTags" class="form-label">Tags (with space and comma separator)</label> <select class="form-select" id="separatorTags" name="tags_separator[]" multiple data-allow-new="true" data-separator=" |,| "> <option value="">Type a tag...</option> <!-- you need at least one option with the placeholder --> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="maxTags" class="form-label">Tags (max 2 tags + clear)</label> <select class="form-select" id="maxTags" name="tags_max[]" multiple data-allow-new="true" data-max="2" data-allow-clear="1" data-suggestions-threshold="0"> <option value="">ㅂㅈㄷㄱㅅㅁㄴㅇㄹㅎㅋㅌㅊ...</option> <!-- you need at least one option with the placeholder --> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> </div> <div class="col-md-4"> <label for="maxTags2" class="form-label">Tags (max 2 tags + clear - already set)</label> <select class="form-select" id="maxTags2" name="tags_max2[]" multiple data-allow-new="true" data-max="2" data-allow-clear="1" data-suggestions-threshold="0"> <option value="">Type a tag...</option> <!-- you need at least one option with the placeholder --> <option value="1" selected>Apple</option> <option value="2" selected>Banana</option> <option value="3">Orange</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="maxTagsBigger" class="form-label">Tags (max 2 tags + clear), but bigger!</label> <select class="form-select form-select-lg" id="maxTagsBigger" name="tags_max_bigger[]" multiple data-allow-new="true" data-max="2" data-allow-clear="1" data-suggestions-threshold="0"> <option value="">ㅂㅈㄷㄱㅅㅁㄴㅇㄹㅎㅋㅌㅊ...</option> <!-- you need at least one option with the placeholder --> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="max1Tags" class="form-label">Tags (max 1 tag + clear)</label> <select class="form-select" id="max1Tags" name="tags_max1[]" multiple data-allow-new="true" data-max="1" data-allow-clear="1" data-suggestions-threshold="0"> <option value="">Type a tag...</option> <!-- you need at least one option with the placeholder --> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="addOnBlur" class="form-label">Add on blur (+ keep open)</label> <select class="form-select" id="addOnBlur" name="addOnBlur[]" multiple data-allow-new="true" data-allow-clear="1" data-add-on-blur="1" data-keep-open="1" data-suggestions-threshold="0"> <option value="">Type a tag...</option> <!-- you need at least one option with the placeholder --> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div class="col-md-4"> <label for="addOnBlurValidation" class="form-label">Add on blur (validation)</label> <select class="form-select" id="addOnBlurValidation" name="addOnBlurValidation[]" multiple data-allow-clear="1" data-add-on-blur="1" data-separator=" |,| " data-suggestions-threshold="0"> <option value="">Type a tag...</option> <!-- you need at least one option with the placeholder --> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div class="col-md-4"> <label for="addOnBlurValidationRegex" class="form-label">Add on blur (validation + email regex)</label> <select class="form-select" id="addOnBlurValidationRegex" name="addOnBlurValidationRegex[]" multiple data-allow-new="true" data-add-on-blur="true" data-separator="| , |" data-allow-clear="1" data-badge-style="secondary" data-regex="^[^\s@]+@[^\s@]+\.[^\s@]+$" data-max="1"> <option value="">Type a tag...</option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="updateOnSelect" class="form-label">Update on select + not found message + max 2 items displayed + custom format + custom create callback</label> <select class="form-select" id="updateOnSelect" name="updateOnSelect[]" multiple data-allow-new="true" data-allow-clear="1" data-add-on-blur="1" data-update-on-select="1" data-autoselect-first="0" data-not-found-message="Create a new tag '{{tag}}' ?" data-suggestions-threshold="0" data-maximum-items="2" data-on-render-item="customItemFormat" data-on-create-item="customOnCreate"> <option value="">Type a tag...</option> <!-- you need at least one option with the placeholder --> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> <option value="4">Orange 2</option> <option value="5">Orange 3</option> <option value="6">Orange 4</option> <option value="7">Orange 5</option> </select> </div> </div> <div class="py-3"> <input type="reset" value="Reset" class="btn btn-outline-dark" /> click reset to see values restored to their original state (including same values) </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="tagsMaxReached" class="form-label">Tags (max 2 already reached)</label> <select class="form-control" id="tagsMaxReached" name="tagsMaxReached" multiple data-allow-clear="true" data-suggestions-threshold="0" data-max="2"> <option selected disabled hidden value="">Choose</option> <option value="1" selected="selected">111</option> <option value="2" selected="selected">222</option> <option value="3" selected="selected">333</option> <option value="4">444</option> <option value="5">555</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="serverSideTags" class="form-label">Tags (onload server side + preselected values + search fields)</label> <select class="form-select" id="serverSideTags" name="server_side_tags[]" multiple data-allow-new="true" data-server="demo.json" data-search-fields="value,label" data-selected="server1,server2"> <option disabled hidden value="">Choose a tag...</option> </select> </div> <div class="col-md-4"> <button id="setitem3">Set item with server</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="searchFieldsTags" class="form-label">Tags with custom search fields</label> <select class="form-select" id="searchFieldsTags" name="searchFieldsTags[]" placeholder="choose item"> </select> <script type="module"> import Tags from "./tags.js"; const data = [ { QIP_NO: "0001", QIP_NAME: "A", QIP_Product: "X" }, { QIP_NO: "0002", QIP_NAME: "B", QIP_Product: "Y" }, { QIP_NO: "0003", QIP_NAME: "C", QIP_Product: "Z" } ]; // Init can reset instance Tags.init("#searchFieldsTags", { items: data, labelField: "QIP_NAME", valueField: "QIP_NO", searchFields: ["QIP_NO", "QIP_NAME", "QIP_Product"], onRenderItem: (item) => `${item.QIP_NO}-${item.QIP_NAME}-${item.QIP_Product}` }, true) document.querySelector('#setitem').addEventListener('click', (ev) => { Tags.getInstance(document.querySelector('#searchFieldsTags')).setItem(["0001"]) }) </script> </div> <div class="col-md-4"> <button id="setitem">Set item</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="serverSideTagsSingle" class="form-label">Tags (onload server side + single value)</label> <select multiple name="person" data-placeholder="Start typing" id="serverSideTagsSingle" data-server="demo-single.json" data-show-all-suggestions="1" data-suggestions-threshold="0" data-allow-clear="1" data-max="1"> <option disabled hidden value="">Choose a person</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="serverSideTagsSelected" class="form-label">Tags (onload server side + selected value)</label> <select multiple name="person2" data-placeholder="Start typing" id="serverSideTagsSelected" data-server="demo-two.json" data-show-all-suggestions="1" data-suggestions-threshold="0" data-allow-clear="1"> <option disabled hidden value="">Choose a person</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="validationTagsJson" class="form-label">Tags (live server side + keep open + full width false)</label> <select class="form-select" id="validationTagsJson" name="tags_json[]" multiple data-allow-new="true" data-server="demo.json" data-live-server="1" data-server-params='{"key":"val"}' data-keep-open="1" data-full-width="0"> <option disabled hidden value="">Choose a tag...</option> <!-- <option value="server1" selected>Server 1</option> --> </select> </div> <div class="col-md-4"> <button type="button" id="upparams">Update params</button> <script type="module"> document.getElementById('upparams').addEventListener('click', (e) => { let inst = document.getElementById('validationTagsJson'); inst.dataset.serverParams = '{"key": "' + Date.now() + '"}'; }) </script> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="liveInitialValue" class="form-label">Tags (live server side + initial value)</label> <select class="form-select" id="liveInitialValue" name="tags_live_initial[]" multiple data-allow-new="true" data-allow-same="false" data-server="demo.json" data-live-server="1" data-items='{"some": "some", "value": "value"}' data-selected="some,value" data-server-params='{"key":"val"}'> <option disabled hidden value="">Choose a tag...</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="liveInitialValueHtml" class="form-label">Tags (live server side + initial value from html)</label> <select class="form-select" id="liveInitialValue" name="tags_live_initial[]" multiple data-allow-new="true" data-server="demo.json" data-live-server="1" data-server-params='{"key":"val"}'> <option disabled hidden value="">Choose a tag...</option> <option value="some" selected="selected">some</option> <option value="value" selected="selected">value</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="emptyTags" class="form-label">Tags (empty + hide drop icon is done automatically)</label> <select class="form-select" id="emptyTags" name="tags_empty[]" multiple data-allow-new="true" placeholder="Type a tag"></select> <!-- you can use the placeholder or data-placeholder attribute instead --> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="disabledTags" class="form-label">Tags (disabled)</label> <select class="form-select" id="disabledTags" name="tags_disabled[]" multiple disabled data-allow-new="true" data-allow-clear="1"> <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> <div class="col-md-4"> <button type="button" class="toggle-enable">Enable</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="singleTags" class="form-label">Tags (single - replace on select)</label> <select class="form-select" id="singleTags" name="tags_single" data-allow-clear="0"> <option value="">Choose a tag...</option> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="tags_city" class="form-label">Tags (city)</label> <select class="form-select" id="tags_city" name="tags_city" data-allow-clear="1" data-suggestions-threshold="0" data-label-field="city" data-value-field="city" data-server="demo.json" data-on-server-response="app.cityResponse"> <option value="">Choose a tag...</option> </select> </div> <div class="col-md-4"> <label for="tags_state" class="form-label">Tags (state)</label> <select class="form-select" id="tags_state" name="tags_state" data-allow-clear="1" data-suggestions-threshold="0" data-label-field="state" data-value-field="state" data-server="demo.json" data-on-server-response="app.cityResponse"> <option value="">Choose a tag...</option> </select> </div> </div> <div class="row mb-3 g-3 source-sans"> <div class="col-md-4"> <label for="sourceSansTags" class="form-label">Tags with custom font and custom class + clear end</label> <select class="form-select" id="sourceSansTags" name="sourceSansTags" multiple data-base-class="mybadge" data-clear-end="1" data-allow-clear="1" data-suggestions-threshold="0"> <option value="">Choose a tag...</option> <option value="1" selected>Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="inputGroupTags" class="form-label">Tags in input group + highlight</label> <div class="input-group"> <span class="input-group-text" id="basic-addon1">Tag</span> <select class="form-select" id="inputGroupTags" name="inputGroupTags[]" multiple data-allow-clear="1" data-highlight-typed="1" data-show-all-suggestions="1" required> <option value="">Choose a tag...</option> <option value="1">Apple</option> <option value="2">Banana</option> <option value="ban_2">Banana 2</option> <option value="ban_3">Banana 3</option> <option value="3">Orange</option> <option value="*crazy$<>value">*crazy$<>value</option> <option value="not=valid\">not=valid\</option> </select> </div> </div> <div class="col-md-4"> <button id="show_suggestions">Show suggestions (external trigger)</button> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4"> <label for="singleTagsFirst" class="form-label">Tags (single - first value selected by default)</label> <select class="form-select" id="singleTagsFirst" name="tags_single_first" data-allow-clear="1" data-suggestions-threshold="0" placeholder="Please select"> <option value="1">Apple</option> <option value="2">Banana</option> <option value="3">Orange</option> </select> </div> </div> <div class="row mb-3 g-3"> <div class="col-md-4" dir="rtl"> <label for="rtlTags" class="form-label">Tags (rtl, not fixed)</label> <select class="form-select" id="rtlTags" name="rtlTags[]" multiple data-allow-clear="true" data-allow-new="true" data-clear-end="true"> <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> <option value="4">Orange 2</option> <option value="5">Orange 3</option> <option value="6">Orange 4</option> <option value="7">Orange 5</option> <option value="8">Orange 6</option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div class="col-md-4" dir="rtl"> <label for="rtlTags2" class="form-label">Tags (rtl, not fixed, full width false)</label> <select class="form-select" id="rtlTags2" name="rtlTags2[]" multiple data-allow-clear="true" data-full-width="0" data-allow-new="true"> <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> <option value="4">Orange 2</option> <option value="5">Orange 3</option> <option value="6">Orange 4</option> <option value="7">Orange 5</option> <option value="8">Orange 6</option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div class="col-md-4" dir="rtl"> <label for="rtlTags3" class="form-label">Tags (rtl, fixed)</label> <select class="form-select" id="rtlTags3" name="rtlTags3[]" multiple data-allow-clear="true" data-fixed="true"> <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> </div> </div> <div class="row mb-3 g-3"> <!-- it may NOT be positioned if it has a set position (relative, absolute, etc)--> <div class="col-md-4" style="height: 80px; background: #ccc; border: 1px solid #666; overflow: hidden"> <label for="validationTagsClearInDiv" class="form-label">Tags (overflow, not fixed)</label> <select class="form-select" id="validationTagsClearInDiv" name="tagsClearInDiv[]" multiple data-allow-clear="true"> <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> <option value="4">Orange 2</option> <option value="5">Orange 3</option> <option value="6">Orange 4</option> <option value="7">Orange 5</option> <option value="8">Orange 6</option> </select> <div class="invalid-feedback">Please select a valid tag.</div> </div> <div c