Giter VIP home page Giter VIP logo

choices's Introduction

Choices.js Actions Status Actions Status npm

A vanilla, lightweight (~19kb gzipped 🎉), configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.

Demo

TL;DR

  • Lightweight
  • No jQuery dependency
  • Configurable sorting
  • Flexible styling
  • Fast search/filtering
  • Clean API
  • Right-to-left support
  • Custom templates

Interested in writing your own ES6 JavaScript plugins? Check out ES6.io for great tutorials! 💪🏼

Sponsored by:

Wanderer Maps logo


Table of Contents

Installation

With NPM:

npm install choices.js

With Yarn:

yarn add choices.js

From a CDN:

Note: There is sometimes a delay before the latest version of Choices is reflected on the CDN.

<!-- Include base CSS (optional) -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/base.min.css"
/>
<!-- Or versioned -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/[email protected]/public/assets/styles/base.min.css"
/>

<!-- Include Choices CSS -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"
/>
<!-- Or versioned -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/[email protected]/public/assets/styles/choices.min.css"
/>

<!-- Include Choices JavaScript (latest) -->
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
<!-- Or versioned -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/public/assets/scripts/choices.min.js"></script>

Or include Choices directly:

<!-- Include base CSS (optional) -->
<link rel="stylesheet" href="public/assets/styles/base.min.css" />
<!-- Include Choices CSS -->
<link rel="stylesheet" href="public/assets/styles/choices.min.css" />
<!-- Include Choices JavaScript -->
<script src="/public/assets/scripts/choices.min.js"></script>

Setup

Note: If you pass a selector which targets multiple elements, the first matching element will be used. Versions prior to 8.x.x would return multiple Choices instances.

  // Pass single element
  const element = document.querySelector('.js-choice');
  const choices = new Choices(element);

  // Pass reference
  const choices = new Choices('[data-trigger]');
  const choices = new Choices('.js-choice');

  // Pass jQuery element
  const choices = new Choices($('.js-choice')[0]);

  // Passing options (with default options)
  const choices = new Choices(element, {
    silent: false,
    items: [],
    choices: [],
    renderChoiceLimit: -1,
    maxItemCount: -1,
    addItems: true,
    addItemFilter: null,
    removeItems: true,
    removeItemButton: false,
    editItems: false,
    allowHTML: true,
    duplicateItemsAllowed: true,
    delimiter: ',',
    paste: true,
    searchEnabled: true,
    searchChoices: true,
    searchFloor: 1,
    searchResultLimit: 4,
    searchFields: ['label', 'value'],
    position: 'auto',
    resetScrollPosition: true,
    shouldSort: true,
    shouldSortItems: false,
    sorter: () => {...},
    placeholder: true,
    placeholderValue: null,
    searchPlaceholderValue: null,
    prependValue: null,
    appendValue: null,
    renderSelectedChoices: 'auto',
    loadingText: 'Loading...',
    noResultsText: 'No results found',
    noChoicesText: 'No choices to choose from',
    itemSelectText: 'Press to select',
    uniqueItemText: 'Only unique values can be added',
    customAddItemText: 'Only values matching specific conditions can be added',
    addItemText: (value) => {
      return `Press Enter to add <b>"${value}"</b>`;
    },
    maxItemText: (maxItemCount) => {
      return `Only ${maxItemCount} values can be added`;
    },
    valueComparer: (value1, value2) => {
      return value1 === value2;
    },
    classNames: {
      containerOuter: 'choices',
      containerInner: 'choices__inner',
      input: 'choices__input',
      inputCloned: 'choices__input--cloned',
      list: 'choices__list',
      listItems: 'choices__list--multiple',
      listSingle: 'choices__list--single',
      listDropdown: 'choices__list--dropdown',
      item: 'choices__item',
      itemSelectable: 'choices__item--selectable',
      itemDisabled: 'choices__item--disabled',
      itemChoice: 'choices__item--choice',
      placeholder: 'choices__placeholder',
      group: 'choices__group',
      groupHeading: 'choices__heading',
      button: 'choices__button',
      activeState: 'is-active',
      focusState: 'is-focused',
      openState: 'is-open',
      disabledState: 'is-disabled',
      highlightedState: 'is-highlighted',
      selectedState: 'is-selected',
      flippedState: 'is-flipped',
      loadingState: 'is-loading',
      noResults: 'has-no-results',
      noChoices: 'has-no-choices'
    },
    // Choices uses the great Fuse library for searching. You
    // can find more options here: https://fusejs.io/api/options.html
    fuseOptions: {
      includeScore: true
    },
    labelId: '',
    callbackOnInit: null,
    callbackOnCreateTemplates: null
  });

Terminology

Word Definition
Choice A choice is a value a user can select. A choice would be equivalent to the <option></option> element within a select input.
Group A group is a collection of choices. A group should be seen as equivalent to a <optgroup></optgroup> element within a select input.
Item An item is an inputted value (text input) or a selected choice (select element). In the context of a select element, an item is equivalent to a selected option element: <option value="Hello" selected></option> whereas in the context of a text input an item is equivalent to <input type="text" value="Hello">

Input Types

Choices works with the following input types, referenced in the documentation as noted.

HTML Element Documentation "Input Type"
<input type="text"> text
<select> select-one
<select multiple> select-multiple

Configuration Options

silent

Type: Boolean Default: false

Input types affected: text, select-one, select-multiple

Usage: Optionally suppress console errors and warnings.

items

Type: Array Default: []

Input types affected: text

Usage: Add pre-selected items (see terminology) to text input.

Pass an array of strings:

['value 1', 'value 2', 'value 3']

Pass an array of objects:

[{
  value: 'Value 1',
  label: 'Label 1',
  id: 1
},
{
  value: 'Value 2',
  label: 'Label 2',
  id: 2,
  customProperties: {
    random: 'I am a custom property'
  }
}]

choices

Type: Array Default: []

Input types affected: select-one, select-multiple

Usage: Add choices (see terminology) to select input.

Pass an array of objects:

[{
  value: 'Option 1',
  label: 'Option 1',
  selected: true,
  disabled: false,
},
{
  value: 'Option 2',
  label: 'Option 2',
  selected: false,
  disabled: true,
  customProperties: {
    description: 'Custom description about Option 2',
    random: 'Another random custom property'
  },
}]

renderChoiceLimit

Type: Number Default: -1

Input types affected: select-one, select-multiple

Usage: The amount of choices to be rendered within the dropdown list ("-1" indicates no limit). This is useful if you have a lot of choices where it is easier for a user to use the search area to find a choice.

maxItemCount

Type: Number Default: -1

Input types affected: text, select-multiple

Usage: The amount of items a user can input/select ("-1" indicates no limit).

addItems

Type: Boolean Default: true

Input types affected: text

Usage: Whether a user can add items.

removeItems

Type: Boolean Default: true

Input types affected: text, select-multiple

Usage: Whether a user can remove items.

removeItemButton

Type: Boolean Default: false

Input types affected: text, select-one, select-multiple

Usage: Whether each item should have a remove button.

editItems

Type: Boolean Default: false

Input types affected: text

Usage: Whether a user can edit items. An item's value can be edited by pressing the backspace.

allowHTML

Type: Boolean Default: true

Input types affected: text, select-one, select-multiple

Usage: Whether HTML should be rendered in all Choices elements. If false, all elements (placeholder, items, etc.) will be treated as plain text. If true, this can be used to perform XSS scripting attacks if you load choices from a remote source.

Deprecation Warning: This will default to false in a future release.

duplicateItemsAllowed

Type: Boolean Default: true

Input types affected: text, select-multiple

Usage: Whether duplicate inputted/chosen items are allowed

delimiter

Type: String Default: ,

Input types affected: text

Usage: What divides each value. The default delimiter separates each value with a comma: "Value 1, Value 2, Value 3".

paste

Type: Boolean Default: true

Input types affected: text, select-multiple

Usage: Whether a user can paste into the input.

searchEnabled

Type: Boolean Default: true

Input types affected: select-one

Usage: Whether a search area should be shown. Note: Multiple select boxes will always show search areas.

searchChoices

Type: Boolean Default: true

Input types affected: select-one

Usage: Whether choices should be filtered by input or not. If false, the search event will still emit, but choices will not be filtered.

searchFields

Type: Array/String Default: ['label', 'value']

Input types affected:select-one, select-multiple

Usage: Specify which fields should be used when a user is searching. If you have added custom properties to your choices, you can add these values thus: ['label', 'value', 'customProperties.example'].

searchFloor

Type: Number Default: 1

Input types affected: select-one, select-multiple

Usage: The minimum length a search value should be before choices are searched.

searchResultLimit: 4,

Type: Number Default: 4

Input types affected: select-one, select-multiple

Usage: The maximum amount of search results to show.

position

Type: String Default: auto

Input types affected: select-one, select-multiple

Usage: Whether the dropdown should appear above (top) or below (bottom) the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it.

resetScrollPosition

Type: Boolean Default: true

Input types affected: select-multiple

Usage: Whether the scroll position should reset after adding an item.

addItemFilter

Type: string | RegExp | Function Default: null

Input types affected: text

Usage: A RegExp or string (will be passed to RegExp constructor internally) or filter function that will need to return true for a user to successfully add an item.

Example:

// Only adds items matching the text test
new Choices(element, {
  addItemFilter: (value) => {
    return ['orange', 'apple', 'banana'].includes(value);
  };
});

// only items ending to `-red`
new Choices(element, {
  addItemFilter: '-red$';
});

shouldSort

Type: Boolean Default: true

Input types affected: select-one, select-multiple

Usage: Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given.

shouldSortItems

Type: Boolean Default: false

Input types affected: text, select-multiple

Usage: Whether items should be sorted. If false, items will appear in the order they were selected.

sorter

Type: Function Default: sortByAlpha

Input types affected: select-one, select-multiple

Usage: The function that will sort choices and items before they are displayed (unless a user is searching). By default choices and items are sorted by alphabetical order.

Example:

// Sorting via length of label from largest to smallest
const example = new Choices(element, {
  sorter: function(a, b) {
    return b.label.length - a.label.length;
  },
};

placeholder

Type: Boolean Default: true

Input types affected: text

Usage: Whether the input should show a placeholder. Used in conjunction with placeholderValue. If placeholder is set to true and no value is passed to placeholderValue, the passed input's placeholder attribute will be used as the placeholder value.

Note: For select boxes, the recommended way of adding a placeholder is as follows:

<select>
  <option value="">This is a placeholder</option>
  <option>...</option>
  <option>...</option>
  <option>...</option>
</select>

For backward compatibility, <option placeholder>This is a placeholder</option> is also supported.

placeholderValue

Type: String Default: null

Input types affected: text

Usage: The value of the inputs placeholder.

searchPlaceholderValue

Type: String Default: null

Input types affected: select-one

Usage: The value of the search inputs placeholder.

prependValue

Type: String Default: null

Input types affected: text, select-one, select-multiple

Usage: Prepend a value to each item added/selected.

appendValue

Type: String Default: null

Input types affected: text, select-one, select-multiple

Usage: Append a value to each item added/selected.

renderSelectedChoices

Type: String Default: auto

Input types affected: select-multiple

Usage: Whether selected choices should be removed from the list. By default choices are removed when they are selected in multiple select box. To always render choices pass always.

loadingText

Type: String Default: Loading...

Input types affected: select-one, select-multiple

Usage: The text that is shown whilst choices are being populated via AJAX.

noResultsText

Type: String/Function Default: No results found

Input types affected: select-one, select-multiple

Usage: The text that is shown when a user's search has returned no results. Optionally pass a function returning a string.

noChoicesText

Type: String/Function Default: No choices to choose from

Input types affected: select-multiple

Usage: The text that is shown when a user has selected all possible choices. Optionally pass a function returning a string.

itemSelectText

Type: String Default: Press to select

Input types affected: select-multiple, select-one

Usage: The text that is shown when a user hovers over a selectable choice.

addItemText

Type: String/Function Default: Press Enter to add "${value}"

Input types affected: text

Usage: The text that is shown when a user has inputted a new item but has not pressed the enter key. To access the current input value, pass a function with a value argument (see the default config for an example), otherwise pass a string.

maxItemText

Type: String/Function Default: Only ${maxItemCount} values can be added

Input types affected: text

Usage: The text that is shown when a user has focus on the input but has already reached the max item count. To access the max item count, pass a function with a maxItemCount argument (see the default config for an example), otherwise pass a string.

valueComparer

Type: Function Default: strict equality

Input types affected: select-one, select-multiple

Usage: A custom compare function used when finding choices by value (using setChoiceByValue).

Example:

const example = new Choices(element, {
  valueComparer: (a, b) => value.trim() === b.trim(),
};

labelId

Type: String Default: ``

Input types affected: select-one, select-multiple

Usage: The labelId improves accessibility. If set, it will add aria-labelledby to the choices element.

classNames

Type: Object Default:

classNames: {
  containerOuter: 'choices',
  containerInner: 'choices__inner',
  input: 'choices__input',
  inputCloned: 'choices__input--cloned',
  list: 'choices__list',
  listItems: 'choices__list--multiple',
  listSingle: 'choices__list--single',
  listDropdown: 'choices__list--dropdown',
  item: 'choices__item',
  itemSelectable: 'choices__item--selectable',
  itemDisabled: 'choices__item--disabled',
  itemOption: 'choices__item--choice',
  group: 'choices__group',
  groupHeading : 'choices__heading',
  button: 'choices__button',
  activeState: 'is-active',
  focusState: 'is-focused',
  openState: 'is-open',
  disabledState: 'is-disabled',
  highlightedState: 'is-highlighted',
  selectedState: 'is-selected',
  flippedState: 'is-flipped',
  selectedState: 'is-highlighted',
}

Input types affected: text, select-one, select-multiple

Usage: Classes added to HTML generated by Choices. By default classnames follow the BEM notation.

Callbacks

Note: For each callback, this refers to the current instance of Choices. This can be useful if you need access to methods (this.disable()) or the config object (this.config).

callbackOnInit

Type: Function Default: null

Input types affected: text, select-one, select-multiple

Usage: Function to run once Choices initialises.

callbackOnCreateTemplates

Type: Function Default: null Arguments: template

Input types affected: text, select-one, select-multiple

Usage: Function to run on template creation. Through this callback it is possible to provide custom templates for the various components of Choices (see terminology). For Choices to work with custom templates, it is important you maintain the various data attributes defined here. If you want just extend a little original template then you may use Choices.defaults.templates to get access to original template function.

Templates receive the full Choices config as the first argument to any template, which allows you to conditionally display things based on the options specified.

Example:

const example = new Choices(element, {
  callbackOnCreateTemplates: () => ({
    input: (...args) =>
      Object.assign(Choices.defaults.templates.input.call(this, ...args), {
        type: 'email',
      }),
  }),
});

or more complex:

const example = new Choices(element, {
  callbackOnCreateTemplates: function(template) {
    return {
      item: ({ classNames }, data) => {
        return template(`
          <div class="${classNames.item} ${
          data.highlighted
            ? classNames.highlightedState
            : classNames.itemSelectable
        } ${
          data.placeholder ? classNames.placeholder : ''
        }" data-item data-id="${data.id}" data-value="${data.value}" ${
          data.active ? 'aria-selected="true"' : ''
        } ${data.disabled ? 'aria-disabled="true"' : ''}>
            <span>&bigstar;</span> ${data.label}
          </div>
        `);
      },
      choice: ({ classNames }, data) => {
        return template(`
          <div class="${classNames.item} ${classNames.itemChoice} ${
          data.disabled ? classNames.itemDisabled : classNames.itemSelectable
        }" data-select-text="${this.config.itemSelectText}" data-choice ${
          data.disabled
            ? 'data-choice-disabled aria-disabled="true"'
            : 'data-choice-selectable'
        } data-id="${data.id}" data-value="${data.value}" ${
          data.groupId > 0 ? 'role="treeitem"' : 'role="option"'
        }>
            <span>&bigstar;</span> ${data.label}
          </div>
        `);
      },
    };
  },
});

Events

Note: Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via this.passedElement. Arguments are accessible within the event.detail object.

Example:

const element = document.getElementById('example');
const example = new Choices(element);

element.addEventListener(
  'addItem',
  function(event) {
    // do something creative here...
    console.log(event.detail.id);
    console.log(event.detail.value);
    console.log(event.detail.label);
    console.log(event.detail.customProperties);
    console.log(event.detail.groupValue);
  },
  false,
);

// or
const example = new Choices(document.getElementById('example'));

example.passedElement.element.addEventListener(
  'addItem',
  function(event) {
    // do something creative here...
    console.log(event.detail.id);
    console.log(event.detail.value);
    console.log(event.detail.label);
    console.log(event.detail.customProperties);
    console.log(event.detail.groupValue);
  },
  false,
);

addItem

Payload: id, value, label, customProperties, groupValue, keyCode

Input types affected: text, select-one, select-multiple

Usage: Triggered each time an item is added (programmatically or by the user).

removeItem

Payload: id, value, label, customProperties, groupValue

Input types affected: text, select-one, select-multiple

Usage: Triggered each time an item is removed (programmatically or by the user).

highlightItem

Payload: id, value, label, groupValue

Input types affected: text, select-multiple

Usage: Triggered each time an item is highlighted.

unhighlightItem

Payload: id, value, label, groupValue

Input types affected: text, select-multiple

Usage: Triggered each time an item is unhighlighted.

choice

Payload: choice

Input types affected: select-one, select-multiple

Usage: Triggered each time a choice is selected by a user, regardless if it changes the value of the input. choice is a Choice object here (see terminology or typings file)

change

Payload: value

Input types affected: text, select-one, select-multiple

Usage: Triggered each time an item is added/removed by a user.

search

Payload: value, resultCount

Input types affected: select-one, select-multiple

Usage: Triggered when a user types into an input to search choices.

showDropdown

Payload: -

Input types affected: select-one, select-multiple

Usage: Triggered when the dropdown is shown.

hideDropdown

Payload: -

Input types affected: select-one, select-multiple

Usage: Triggered when the dropdown is hidden.

highlightChoice

Payload: el

Input types affected: select-one, select-multiple

Usage: Triggered when a choice from the dropdown is highlighted. The el argument is choices.passedElement object that was affected.

Methods

Methods can be called either directly or by chaining:

// Calling a method by chaining
const choices = new Choices(element, {
  addItems: false,
  removeItems: false,
})
  .setValue(['Set value 1', 'Set value 2'])
  .disable();

// Calling a method directly
const choices = new Choices(element, {
  addItems: false,
  removeItems: false,
});

choices.setValue(['Set value 1', 'Set value 2']);
choices.disable();

destroy();

Input types affected: text, select-multiple, select-one

Usage: Kills the instance of Choices, removes all event listeners and returns passed input to its initial state.

init();

Input types affected: text, select-multiple, select-one

Usage: Creates a new instance of Choices, adds event listeners, creates templates and renders a Choices element to the DOM.

Note: This is called implicitly when a new instance of Choices is created. This would be used after a Choices instance had already been destroyed (using destroy()).

highlightAll();

Input types affected: text, select-multiple

Usage: Highlight each chosen item (selected items can be removed).

unhighlightAll();

Input types affected: text, select-multiple

Usage: Un-highlight each chosen item.

removeActiveItemsByValue(value);

Input types affected: text, select-multiple

Usage: Remove each item by a given value.

removeActiveItems(excludedId);

Input types affected: text, select-multiple

Usage: Remove each selectable item.

removeHighlightedItems();

Input types affected: text, select-multiple

Usage: Remove each item the user has selected.

showDropdown();

Input types affected: select-one, select-multiple

Usage: Show option list dropdown (only affects select inputs).

hideDropdown();

Input types affected: text, select-multiple

Usage: Hide option list dropdown (only affects select inputs).

setChoices(choices, value, label, replaceChoices);

Input types affected: select-one, select-multiple

Usage: Set choices of select input via an array of objects (or function that returns array of object or promise of it), a value field name and a label field name.

This behaves the similar as passing items via the choices option but can be called after initialising Choices. This can also be used to add groups of choices (see example 3); Optionally pass a true replaceChoices value to remove any existing choices. Optionally pass a customProperties object to add additional data to your choices (useful when searching/filtering etc). Passing an empty array as the first parameter, and a true replaceChoices is the same as calling clearChoices (see below).

Example 1:

const example = new Choices(element);

example.setChoices(
  [
    { value: 'One', label: 'Label One', disabled: true },
    { value: 'Two', label: 'Label Two', selected: true },
    { value: 'Three', label: 'Label Three' },
  ],
  'value',
  'label',
  false,
);

Example 2:

const example = new Choices(element);

// Passing a function that returns Promise of choices
example.setChoices(async () => {
  try {
    const items = await fetch('/items');
    return items.json();
  } catch (err) {
    console.error(err);
  }
});

Example 3:

const example = new Choices(element);

example.setChoices(
  [
    {
      label: 'Group one',
      id: 1,
      disabled: false,
      choices: [
        { value: 'Child One', label: 'Child One', selected: true },
        { value: 'Child Two', label: 'Child Two', disabled: true },
        { value: 'Child Three', label: 'Child Three' },
      ],
    },
    {
      label: 'Group two',
      id: 2,
      disabled: false,
      choices: [
        { value: 'Child Four', label: 'Child Four', disabled: true },
        { value: 'Child Five', label: 'Child Five' },
        {
          value: 'Child Six',
          label: 'Child Six',
          customProperties: {
            description: 'Custom description about child six',
            random: 'Another random custom property',
          },
        },
      ],
    },
  ],
  'value',
  'label',
  false,
);

clearChoices();

Input types affected: select-one, select-multiple

Usage: Clear all choices from select

getValue(valueOnly)

Input types affected: text, select-one, select-multiple

Usage: Get value(s) of input (i.e. inputted items (text) or selected choices (select)). Optionally pass an argument of true to only return values rather than value objects.

Example:

const example = new Choices(element);
const values = example.getValue(true); // returns ['value 1', 'value 2'];
const valueArray = example.getValue(); // returns [{ active: true, choiceId: 1, highlighted: false, id: 1, label: 'Label 1', value: 'Value 1'},  { active: true, choiceId: 2, highlighted: false, id: 2, label: 'Label 2', value: 'Value 2'}];

setValue(items);

Input types affected: text

Usage: Set value of input based on an array of objects or strings. This behaves exactly the same as passing items via the items option but can be called after initialising Choices.

Example:

const example = new Choices(element);

// via an array of objects
example.setValue([
  { value: 'One', label: 'Label One' },
  { value: 'Two', label: 'Label Two' },
  { value: 'Three', label: 'Label Three' },
]);

// or via an array of strings
example.setValue(['Four', 'Five', 'Six']);

setChoiceByValue(value);

Input types affected: select-one, select-multiple

Usage: Set value of input based on existing Choice. value can be either a single string or an array of strings

Example:

const example = new Choices(element, {
  choices: [
    { value: 'One', label: 'Label One' },
    { value: 'Two', label: 'Label Two', disabled: true },
    { value: 'Three', label: 'Label Three' },
  ],
});

example.setChoiceByValue('Two'); // Choice with value of 'Two' has now been selected.

clearStore();

Input types affected: text, select-one, select-multiple

Usage: Removes all items, choices and groups. Use with caution.

clearInput();

Input types affected: text

Usage: Clear input of any user inputted text.

disable();

Input types affected: text, select-one, select-multiple

Usage: Disables input from accepting new value/selecting further choices.

enable();

Input types affected: text, select-one, select-multiple

Usage: Enables input to accept new values/select further choices.

Browser compatibility

Choices is compiled using Babel targeting browsers with more than 1% of global usage and expecting that features listed below are available or polyfilled in browser. You may see exact list of target browsers by running npx browserslist within this repository folder. If you need to support a browser that does not have one of the features listed below, I suggest including a polyfill from the very good polyfill.io:

Polyfill example used for the demo:

<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=Array.from%2Ces5%2Ces6%2CSymbol%2CSymbol.iterator%2CDOMTokenList%2CObject.assign%2CCustomEvent%2CElement.prototype.classList%2CElement.prototype.closest%2CElement.prototype.dataset%2CArray.prototype.find%2CArray.prototype.includes"></script>

Features used in Choices:

Array.from
Array.prototype.find
Array.prototype.includes
Symbol
Symbol.iterator
DOMTokenList
Object.assign
CustomEvent
Element.prototype.classList
Element.prototype.closest
Element.prototype.dataset

Development

To setup a local environment: clone this repo, navigate into its directory in a terminal window and run the following command:

npm install

NPM tasks

Task Usage
npm run start Fire up local server for development
npm run test:unit Run sequence of tests once
npm run test:unit:watch Fire up test server and re-test on file change
npm run test:e2e Run sequence of e2e tests (with local server)
npm run test Run both unit and e2e tests
npm run cypress:open Run Cypress e2e tests (GUI)
npm run cypress:run Run Cypress e2e tests (CLI)
npm run js:build Compile Choices to an uglified JavaScript file
npm run css:watch Watch SCSS files for changes. On a change, run build process
npm run css:build Compile, minify and prefix SCSS files to CSS

Interested in contributing?

We're always interested in having more active maintainers. Please get in touch if you're interested 👍

License

MIT License

Web component

Want to use Choices as a web component? You're in luck. Adidas have built one for their design system which can be found here.

Misc

Thanks to @mikefrancis for sending me on a hunt for a non-jQuery solution for select boxes that eventually led to this being built!

choices's People

Contributors

actions-user avatar adammockor avatar alexwlchan avatar arthurvasconcelos avatar bjjlangedijk avatar dependabot[bot] avatar dmitrach avatar jaykid avatar jhou avatar jshjohnson avatar kostkobv avatar mason-rogers avatar maximmig avatar mike-robertson avatar mtriff avatar mysliwietzflorian avatar nathanielw avatar p-bernal avatar paullaros avatar razh avatar rjorel avatar rstacruz avatar ryan-mahoney avatar samueldjack avatar spone avatar stephanetrebel avatar stof avatar tinovyatkin avatar yabab-dev avatar zackschuster 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  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

choices's Issues

Always selects first item in select-multiple element

There is a bug in the library that causes the first option in a select-multiple element to always be selected when the Choices object is initialised.

This is where it happens (line 1864 of src/choices.js)

// Join choices with preset choices and add them
allChoices
    .concat(this.presetChoices)
    .forEach((o, index) => {
        if (index === 0) {
            this._addChoice(true, o.disabled ? o.disabled : false, o.value, o.label);
        } else {
            this._addChoice(o.selected ? o.selected : false, o.disabled ? o.disabled : false, o.value, o.label);
        }
    });

The if (index === 0) { should be changed to take into account the select element type, like it does elsewhere in the script. i.e.

if (index === 0 && this.passedElement.type === 'select-one') {

Sorry I can't give you a patch but after wasting an hour or so unsuccessfully trying to get node.js and a long list of dependencies installed (webpack, eslint, opn, babel etc etc etc) so I can build a non-minified script that executes, I gave up and just edited the minified version instead. I'm not sure if "this" will work in the closure but the minified version inserts a named variable "e" pointing to "this" which does work.

It would be great if you could include a fully compiled, non-minified, source script in the distribution so that we can easily debug without having to mess around with node.js and/or reverse engineering the minified version. Thanks.

Variablize style class names

Hey!
Currently when instantiating Choices, you can impact the naming of the UI classes, but https://github.com/jshjohnson/Choices/blob/master/assets/styles/scss/choices.scss doesn't have a way to override these selectors if you'd like to keep the base styles (as far as I can see). Would you be up for a way to plug into these values? It'd look something like this:

$choices-selector: 'choices' !default;

.#{$choices-selector} {
  color: blue;
}

It's something I could look into if you're interested.

Set and get selected values (on select elements)

I need to set and get selected element, like we do on select elements, only by send/return the values of selected choice(s).
(Like we do with jQuery : $('select').val(value);)

Today, if i use setValue() function, I need to pass an object like {value: 'one', label: 'Label One'} right ?
If so, i'have some issues with it : https://embed.plnkr.co/t48jwB4R7TunhXwcsr5z/

I've done an attempt to demonstrate clearly what i need : yabab-dev@5c8d91d

If you need a PR, ask me.

Thanks for you time !

(And sorry for spamming issues :p)

IE11 - Single select

Hi!
Not necessarily a bug, but a difference in behavior than other browsers - when selecting a single-select in IE11, the dropdown remains open, compared to Chrome, Firefox, and Safari (latest) it's closed on selection. I'll see if I can spot anything unless you come across anything quicker. Thanks!

'items' config not working with select-one element

Hi,
First : awesome library !

I'm trying to make a angular 2 wrapper of your plugin and I think I've spotted some bugs, first of them, the config "items" seems to not work with a select-one element.

Here is a demo (#choices-1) : https://embed.plnkr.co/hVyjk5z2lJZorqOi48e6/
The list remain empty.

Maybe I don't use this variable correctly ?

(I've grouped all bugs on the same plunker, I'll do a different issue for other bug)

Thanks !

Placeholder display on the search text input and not on the select

When I am setting a placeholder, my expectation is to see the placeholder on the select element and not on the search input when clicking the select box.

How can I set a placeholder for the users to see when there is no value selected?

My example plunker:
plunker

Thanks. ( By the way awesome plugin )

Export react component

Not sure if this would be possible but it'd be SUPER cool if you exported a react component as well.

Don't remove original DOM node

Frameworks like Vue.js rely on certain DOM nodes to not be removed by third-party code to work properly. (See vuejs/vue#3302). I think simply hiding the original DOM node would be a better option here. Thoughts?

problems to import using RequireJs

when we try to use choices.js with requirejs the lib is loaded but, no return is provided.

To demonstrate the problem I have created a sample project to show how I am trying to use choices with requirejs

https://github.com/herbertpimentel/choicesjs_test

to run this you just need:

Install bower globally using npm

> npm install -g bower 

Install the bower dependences

>bower install 

As I hove you will see choices is successful loaded but I receive a message TypeError: Choices is not a constructor... when I try to use it.

maybe it is something with webpack export. I am very curious about it

Don't flip drop down on mobile and ensure search is in view

When on mobile the drop down should only flip if there is no space beyond the document height rather than the viewport height. This avoids the drop down changing between being above and below the input when a choice is selected. The search should also always be visible within the viewport (possibly scroll to the input upon focus).

Consider not minifying

...or leaving choices.js as the "main" entrypoint, instead of choices.min.js.

This lets others debug properly :)

callbackOnChange isn't triggered when backspacing an item

From the description in the readme, it seems like the callbackOnChange callback should be called when an item is added or removed via any sort of user-input. Currently removing an item only triggers it if an item is removed using the button, not if it is backspaced.
Seems like it should be called after line 817.

Dependent Dropdown

It would be really nice to have a feature to make dependent dropdowns. For example, let's imagine we have 2 dropdowns:

  • Dropdown 1 is independent. Dropdown 2 depends on dropdown 1 value.
  • Dropdown 1 is enabled by default while dropdown 2 is disabled until dropdown 1 has a selected value.
  • An event is fired after a value has been selected in dropdown 1.
  • The default behavior of the selected-value-event should be: if a non-null value has been selected in dropdown 1, then enable dropdown 2.
  • An optional anonymous function should be passed to allow custom validations to enable or reject the enabling of the dropdown 2.

Just an idea, but I would really love a functionality like this since mostly all of the existing solutions require jQuery.

Get the value of the group

There is a way to get the value of the group?

    const example = new Choices(ele);

    example.setChoices([{
      label: 'Personal',
      choices: [
        {value: 'Child One', label: 'Child One'},
        {value: 'Child Two', label: 'Child Two'}
      ]
    },
      {
        label: 'Internet',
        choices: [
          {value: 'Child One', label: 'Child One'},
          {value: 'Child Two', label: 'Child Two'}
        ]
      }], 'value', 'label');
  }

So for example here when I click on item in the Personal group I need to know the group name.

Can't select text with a mouse

I saw your post on /r/coolgithubprojects. I noticed on your demo page, using Chrome 52.0.2743.82, that selecting text doesn't work with the mouse. I can use the keyboard (shift + arrow keys), and Select All from the context menu, but the only mouse functionality available is focus. It won't even move the cursor around between characters.

Add way to build a really lightweight version or make it more modular

You talk about a lightweight version but I think it's way to bloated for simple use cases (for example if you just want to use a single select input with search functionality).

Status quo:
chosen.min.js | 28kb
selectivity.min.js | 50kb
choices.min.js | 61kb
select2.min.js | 67kb

It would be nice if it is possible to build an own custom build or (better) you make it modular like selectivity.js.

Webpack vs Rollup

Hey!
Wanted to bring up more a discussion rather than an issue, but I recently read through https://nolanlawson.com/2016/08/15/the-cost-of-small-modules/ which had some interesting insights into some of the extra "stuff" Webpack can wrap around your code which can sometimes lead to larger file sizes - and wanted to get your take. About to do some integration work with Choices to replace Chosen (which relies on jQuery), but noticed the distributed size is about the same of both Chosen and jQuery combined - and it came across a little odd. Thanks!

Clear choices on search

Wanted to use this with remote data, Im prb just using it wrong
But what I wanted to repopulate the dropdown when trying into the search box
Nothing have to be changed without user selection a row
Thx

      this.Choices = new choises(this.element,{
      callbackOnChange : (value) => {
          //this triggers, ok
      },
      callbackOnSearch : (value)=>{
        //this triggers, but setvalue cant be used, it just adds all the time, and set input value to one of the rows
//tried setChoises to but nothing happend

      }
    });

Question about Fetch API

Is it be possible to make a other request to fetch API in case no results found and to pass the entered value as argument and offer the response as new select data? If yes exist any example?

As is now it preloads the data and the user can select from this initial data fetch. In a case where many records exist, this is not the ideal solution.

classNames JS object

Hey!
When trying to customize the classNames object during initialization and only impact a single value, it looks like Choices was blowing up a little and not working as expected until I pasted all the default values and customized one of them. Is the intended behavior to need to dupe all the defaults in this area? Thanks!

Usage in another React application?

Any chance you've used this inside another react+redux application? if so how? i've tried importing it and using it htat way but i get unexpected token inport errors?

Loading text not replaced

Hi,

When using Choices in 'multiple mode', the "Loading..." text is not replaced if "placeholderValue" is not set or if 'placeholder' is set to "false".
choices - loading

Thanks.

Is there a easy way to just set height/width ?

Is there a easy way to just set height/width ?
Or get it to follow the select you add it too?
Or do you have a bootstrap theme so it really looks like it belongs with the rest of the form elements?

Thx, looks really cool, love its vanilla js

Use Disabled Option as "Placeholder"

Would it be possible to have this plugin work with a disabled attribute so an <option> can be used as a placeholder? In a traditional <select> you could do the following to achieve this:

<select id="dropdown-save-to-project" class="form-control">
    <option disabled selected>Choose Project..</option>
    <option>Project #1 </option>
    <option>Project #2</option>
    <option>New Project</option>
</select>

When using choices, the <select> is shown empty until a non-disabled element is selected. I also tried using the built in placeholder/placeholderValue options but could not get it working with a single select input and didn't see any examples on the demo page.

(I also think this would degrade nicely if you opted to use a traditional <select> for mobile.)

<label><select></label> doesn't open when clicked

I have something like this:

<label>
   <select id='x'>...</select>
</label>
new Choices(document.getElementById('x'))

But I can't click it. I can press spacebar on it just fine, though.

It seems like it opens the dropdown, then closes it immediately:

            } else if (this.passedElement.type === 'select-one' && target !== this.input && !this.dropdown.contains(target)) {
              this.hideDropdown(true);
            }

this is indeed !== this.input. and this.dropdown indeed doesn't have target:

image

What happens here is that two click events happen.

Server side filtering

Hi,

I'd like to add a server-side filtering feature which would fetch data as the user inputs text (with a 'minChars' and a 'delay' properties).

Is that something that you plan to add in a future release ?

Thanks

dist/choices.min.js does not export a variable

The main dist file doesn't export a useful value. It simply gives you {}.

import Choices from 'choices.js'
new Choices()  // Error: Choices is not a function
console.log(Choices)  // => Object {}

Same effect with require().

var Choices = require('choices.js')
new Choices()  // Error: Choices is not a function
console.log(Choices)  // => Object {}

What it actually does is export window.Choices. This works, contrary to commonjs expectations:

require('choices.js')
new window.Choices(element)

cc @akosipc who first encountered this bug.

User add item & multi-select

Is it possible to mix multi-select with the users ability to add custom items? Or alternatively, give the text field some predefined suggestions in the style of the multi-select?

I've tried setting the choices option when targeting a text field, but it doesn't seem to work.

Mimicking Checkbox Behavior

Hi there,

Choices looks like what I've been looking around for so long! Thanks for making it.
There are multi-select dropdowns, is there a way to have those options within a multiselect to be checkboxes instead of the current DIVs under a tag? Thanks!

CSS uses too much nesting sometimes

For instance:

.choices__group .choices__heading {

...when you can just use .choices__heading. I typically restyle Choices.js to fit the project I'm working on, and using less-specific CSS selectors would help a lot.

Keyboard actions seem off

Hi,
Appreciate all the hard work going on here! Noticed something a little odd when interacting with the dropdowns with my keyboard; when I attempt to filter a list, the current selected position seems to jump around a bit.

screenflow

The above is with remote sources, but I've also seen this happen with Multiple Select Input. 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.