# Choices-Vue3

[![npm version](https://img.shields.io/npm/v/choices-vue3.svg)](https://www.npmjs.com/package/choices-vue3) [![npm downloads](https://img.shields.io/npm/dm/choices-vue3.svg)](https://www.npmjs.com/package/choices-vue3) [![Vue 3 Compatible](https://img.shields.io/badge/vue-3.x-brightgreen.svg)](https://vuejs.org/) [![Types Included](https://img.shields.io/npm/types/choices-vue3.svg)](https://www.npmjs.com/package/choices-vue3) [![](https://data.jsdelivr.com/v1/package/npm/choices-vue3/badge?style=rounded)](https://www.jsdelivr.com/package/npm/choices-vue3)

💡 A lightweight and flexible Vue 2 & Vue 3 wrapper for Choices.js, fully compatible with Bootstrap 5 and written in TypeScript.
Supports CDN and bundled usage, v-model binding, custom events, async search, and multiple selection modes — all without relying on jQuery.


---


## 🖼️ Preview

![Choices-Vue3 Preview](https://res.cloudinary.com/doftx5wrm/image/upload/v1752425173/demo_choice_pqvcab.jpeg)

---



## 🧪 Demo & Playground
🔗 [Try at JSFiddle](https://jsfiddle.net/ryuhiro/xq82L7mn/7/)


## 🚀 Install

### With npm (recommended)

```bash
npm install choices-vue3
```

### With CDN

```bash
<link href="https://cdn.jsdelivr.net/npm/choices-vue3@1.0.0/dist/choices-vue3.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/choices-vue3@1.0.0/dist/choices-vue3.min.js"></script>
```

## 🧩 Usage

### Basic usage (npm / bundler)
```bash
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { useChoices } from 'choices-vue3'
import 'choices-vue3/dist/vue3/choices-vue3.css'

const app = createApp(App)

app.use(useChoices)
app.mount('#app')
```

as a component? Or for TypeScript when build (Tested in Vite when using `npm run build`):

```bash
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import { ChoicesVue3 } from 'choices-vue3/vue3' or import ChoicesVue3 from 'choices-vue3/vue3'
import 'choices-vue3/dist/vue3/choices-vue3.css'

const app = createApp(App)

app.component('choices-vue3', ChoicesVue3)
app.mount('#app')
```

Now use in your any components:

## As Single Select (Default)
```bash
<template>
  <choices-vue3
    v-model="selectedValue"
    :options="selectOptions"
    @change="handleChange"
    class="mb-2"
    :placeholder="'Select an option'"
  ></choices-vue3>
</template>

<script setup>
import { ref } from 'vue'

const selectedValue = ref(null)
const selectOptions = ref([
  { value: '1a2b3c4d', label: 'Admin - Budi Santoso' },
  { value: '2b3c4d5e', label: 'Marketing - Siti Aminah' },
  { value: '3c4d5e6f', label: 'Developer - Agus Wijaya' },
  { value: '4d5e6f7g', label: 'HR - Indah Permata' },
  { value: '5e6f7g8h', label: 'Finance - Rudi Hartono' },
  { value: '6f7g8h9i', label: 'QA - Tono Supriyadi' },
  { value: '7g8h9i0j', label: 'Design - Sarah Maharani' },
  { value: '8h9i0j1k', label: 'Support - Dimas Ananta' },
  { value: '9i0j1k2l', label: 'PM - Citra Larasati' },
  { value: '0j1k2l3m', label: 'Intern - Yoga Pranata' },
])
</script>
```

Or you can use TypeScript:

```bash
<template>
  <choices-vue3
    v-model="selectedValue"
    :options="selectOptions"
    @change="handleChange"
    class="mb-2"
    :placeholder="'Select an option'"
  ></choices-vue3>
/>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  name: 'HelloWorld',
  setup() {
    const selectedValue = ref('')
    const selectOptions = ref([
      { value: '1a2b3c4d', label: 'Admin - Budi Santoso' },
      { value: '2b3c4d5e', label: 'Marketing - Siti Aminah' },
      { value: '3c4d5e6f', label: 'Developer - Agus Wijaya' },
      { value: '4d5e6f7g', label: 'HR - Indah Permata' },
      { value: '5e6f7g8h', label: 'Finance - Rudi Hartono' },
      { value: '6f7g8h9i', label: 'QA - Tono Supriyadi' },
      { value: '7g8h9i0j', label: 'Design - Sarah Maharani' },
      { value: '8h9i0j1k', label: 'Support - Dimas Ananta' },
      { value: '9i0j1k2l', label: 'PM - Citra Larasati' },
      { value: '0j1k2l3m', label: 'Intern - Yoga Pranata' },
    ])

    return {
      selectedValue,
      selectOptions,
    }
  }
})
</script>
```


## As Multiple Select
```bash
<template>
  <choices-vue3
    v-model="selectedValue"
    :options="selectOptions"
    @change="handleChange"
    class="mb-2"
    :placeholder="'Select an option'"
    :config="{ mode: 'multiple', delimiter: ',', removeItemButton: true, removeItems: true, setting: { returnObject: false }}"
    :multiple="true"
  ></choices-vue3>
</template>

<script setup>
import { ref } from 'vue'

const selectedValue = ref(null)
const selectOptions = ref([
  { value: '1a2b3c4d', label: 'Admin - Budi Santoso' },
  { value: '2b3c4d5e', label: 'Marketing - Siti Aminah' },
  { value: '3c4d5e6f', label: 'Developer - Agus Wijaya' },
  { value: '4d5e6f7g', label: 'HR - Indah Permata' },
  { value: '5e6f7g8h', label: 'Finance - Rudi Hartono' },
  { value: '6f7g8h9i', label: 'QA - Tono Supriyadi' },
  { value: '7g8h9i0j', label: 'Design - Sarah Maharani' },
  { value: '8h9i0j1k', label: 'Support - Dimas Ananta' },
  { value: '9i0j1k2l', label: 'PM - Citra Larasati' },
  { value: '0j1k2l3m', label: 'Intern - Yoga Pranata' },
])
</script>
```

Or you can use TypeScript:

```bash
<template>
  <choices-vue3
    v-model="selectedValue"
    :options="selectOptions"
    @change="handleChange"
    class="mb-2"
    :placeholder="'Select an option'"
    :config="{ mode: 'multiple', delimiter: ',', removeItemButton: true, removeItems: true, setting: { returnObject: true }}"
    :multiple="true"
  ></choices-vue3>
/>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  name: 'HelloWorld',
  setup() {
    const selectedValue = ref('')
    const selectOptions = ref([
      { value: '1a2b3c4d', label: 'Admin - Budi Santoso' },
      { value: '2b3c4d5e', label: 'Marketing - Siti Aminah' },
      { value: '3c4d5e6f', label: 'Developer - Agus Wijaya' },
      { value: '4d5e6f7g', label: 'HR - Indah Permata' },
      { value: '5e6f7g8h', label: 'Finance - Rudi Hartono' },
      { value: '6f7g8h9i', label: 'QA - Tono Supriyadi' },
      { value: '7g8h9i0j', label: 'Design - Sarah Maharani' },
      { value: '8h9i0j1k', label: 'Support - Dimas Ananta' },
      { value: '9i0j1k2l', label: 'PM - Citra Larasati' },
      { value: '0j1k2l3m', label: 'Intern - Yoga Pranata' },
    ])

    return {
      selectedValue,
      selectOptions,
    }
  }
})
</script>
```

## As Tagging
```bash
<template>
  <choices-vue3
    v-model="selectedValue"
    :options="selectOptions"
    @change="handleChange"
    class="mb-2"
    :placeholder="'Select an option'"
    :config="{ mode: 'tagging', delimiter: ',', removeItemButton: true, removeItems: true, setting: { returnObject: false }}"
    :multiple="true"
  ></choices-vue3>
</template>

<script setup>
import { ref } from 'vue'

const selectedValue = ref(null)
const selectOptions = ref([])
</script>
```

Or you can use TypeScript:

```bash
<template>
  <choices-vue3
    v-model="selectedValue"
    :options="selectOptions"
    @change="handleChange"
    class="mb-2"
    :placeholder="'Select an option'"
    :config="{ mode: 'tagging', delimiter: ',', removeItemButton: true, removeItems: true, setting: { returnObject: true }}"
    :multiple="true"
  ></choices-vue3>
/>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue'

export default defineComponent({
  name: 'HelloWorld',
  setup() {
    const selectedValue = ref(null)
    const selectOptions = ref([])

    return {
      selectedValue,
      selectOptions,
    }
  }
})
</script>
```


# How to use the props?

| Prop            | Type                            | Default               | Required | Description                                          |
|-----------------|---------------------------------|-----------------------|----------|------------------------------------------------------|
| `id`            | `String`                        | `'choices'`           | ✘        | The ID attribute for the main element                |
| `name`          | `String`                        | `'choices'`           | ✘        | The name attribute for form input                   |
| `options`       | `Array`                         | —                     | ✔        | List of available options                           |
| `modelValue`    | `String` \| `Number` \| `Array` | `null`                | ✘        | Selected value (used with `v-model`)                |
| `placeholder`   | `String`                        | `'Select an option'`  | ✘        | Placeholder text when no option is selected         |
| `multiple`      | `Boolean`                       | `false`               | ✘        | Enables multiple selection                          |
| `disabled`      | `Boolean`                       | `false`               | ✘        | Disables the component                              |
| `required`      | `Boolean`                       | `false`               | ✘        | Marks the field as required                         |
| `valueKey`      | `String`                        | `'value'`             | ✘        | Key used to extract value from option object        |
| `textKey`       | `String`                        | `'label'`             | ✘        | Key used to extract display text from option object |
| `config`        | `Object`                        | `() => ({})`          | ✘        | Additional configuration options                    |
| `fetchOnSearch` | `Boolean`                       | `false`               | ✘        | Emits `search` event on user input                  |
| `loadingSelect` | `Boolean`                       | `undefined`           | ✘        | Shows loading indicator when true                   |

# Emits

| Event                | Payload                            | Description                                               |
|----------------------|------------------------------------|-----------------------------------------------------------|
| `update:modelValue`  | `String` \| `Number` \| `Array`    | Emitted when the selected value changes                   |
| `change`             | Selected option(s)                 | Emitted when an option is selected                        |
| `search`             | `String`                           | Emitted when the user types in the input field            |
| `loadMore`           | —                                  | Emitted to load more data (e.g., for infinite scrolling)  |

### 📘 Configuration Notes

The `config` prop allows you to customize the behavior of the select component. Below are the guidelines for using it in different modes:

---

#### 🔹 Single Select

- You do **not** need to set `multiple`.
- The `config` prop is **optional**.
- Example (with optional features enabled):

```bash
<MySelect
  :config="{
    removeItemButton: true,
    removeItems: true,
    setting: { returnObject: false }
  }"
/>
```

---

#### 🔸 Multiple Select

- You **must** set `multiple` to `true`.
- You **must** provide a valid `config` with `mode` set to either `'multiple'` or `'tagging'`.

##### Example – Mode: `'multiple'`

```bash
<MySelect
  multiple
  :config="{
    mode: 'multiple',
    delimiter: ',',
    removeItemButton: true,
    removeItems: true,
    setting: { returnObject: false }
  }"
/>
```

##### Example – Mode: `'tagging'`

```bash
<MySelect
  multiple
  :config="{
    mode: 'tagging',
    delimiter: ',',
    removeItemButton: true,
    removeItems: true,
    setting: { returnObject: false }
  }"
/>
```

---

### ⚙️ About `returnObject`

Inside `config.setting`, the `returnObject` option controls what value gets emitted and bound via `v-model`:

| Setting                | Behavior                                                                 |
|------------------------|--------------------------------------------------------------------------|
| `returnObject: false`  | Emits only the `value` from the selected item (based on `valueKey`).     |
| `returnObject: true`   | Emits the **entire object** of the selected item. Useful when you need access to more fields. |

##### Example
```js
// Given options:
[
  { label: 'Apple', value: 'apple', category: 'fruit' },
  { label: 'Carrot', value: 'carrot', category: 'vegetable' }
]

// With returnObject: false
modelValue === 'apple'

// With returnObject: true
modelValue === { label: 'Apple', value: 'apple', category: 'fruit' }
```

Make sure you choose the `returnObject` behavior based on whether your app needs only the value or the entire item object.

---

## 🚀 About Me
I'm a full stack developer...


## Authors

- [@ryuhiro](https://www.github.com/ryuhiro)

