├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── config.yml │ └── feature_request.md └── workflows │ ├── release.yml │ └── test.yml ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── LICENSE.md ├── README.md ├── bower.json ├── build ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── dev ├── Dev.vue ├── dev.html └── dev.js ├── docs ├── .env.example ├── .vuepress │ ├── components │ │ ├── BetterNoOptions.vue │ │ ├── ClearButtonOverride.vue │ │ ├── CodePen.vue │ │ ├── Contributors.vue │ │ ├── CountrySelect.vue │ │ ├── CssSpecificity.vue │ │ ├── CssVariables.vue │ │ ├── CustomComponentRegistration.vue │ │ ├── CustomHandlers.vue │ │ ├── FuseFilter.vue │ │ ├── InfiniteScroll.vue │ │ ├── LimitSelectionQuantity.vue │ │ ├── LoopedSelect.vue │ │ ├── MultipleClearButtonOverride.vue │ │ ├── OpenIndicatorOverride.vue │ │ ├── OpenWhenSearchTextPresent.vue │ │ ├── Paginated.vue │ │ ├── PositionedWithPopper.vue │ │ ├── ReducedWithNoMatchingOption.vue │ │ ├── ReducerNestedValue.vue │ │ ├── Sandbox.vue │ │ ├── SlotFooter.vue │ │ ├── SlotHeader.vue │ │ ├── SlotListFooter.vue │ │ ├── SlotListHeader.vue │ │ ├── SlotNoOptions.vue │ │ ├── SlotOpenIndicator.vue │ │ ├── SlotOption.vue │ │ ├── SlotSearch.vue │ │ ├── SlotSelectedOption.vue │ │ ├── SlotSelectedOptionContainer.vue │ │ ├── SlotSpinner.vue │ │ ├── SponsorBanner.vue │ │ ├── Sponsors.vue │ │ ├── TagOnComma.vue │ │ ├── UnselectableExample.vue │ │ └── ValidationRequired.vue │ ├── config.js │ ├── config │ │ ├── head.js │ │ ├── meta.js │ │ ├── plugins.js │ │ └── themeConfig.js │ ├── data │ │ ├── books.js │ │ ├── countries.js │ │ └── countryCodes.js │ ├── enhanceApp.js │ ├── github │ │ ├── clientDynamicModules.js │ │ └── index.js │ ├── theme │ │ ├── components │ │ │ └── EthicalAds.vue │ │ ├── index.js │ │ └── layouts │ │ │ └── Layout.vue │ └── utils │ │ └── codePen.js ├── README.md ├── api │ ├── events.md │ ├── props.md │ └── slots.md ├── contributors.md ├── guide │ ├── accessibility.md │ ├── ajax.md │ ├── components.md │ ├── css.md │ ├── examples.md │ ├── filtering.md │ ├── infinite-scroll.md │ ├── install.md │ ├── keydown.md │ ├── localization.md │ ├── loops.md │ ├── mixins.md │ ├── opening.md │ ├── options.md │ ├── pagination.md │ ├── positioning.md │ ├── selectable.md │ ├── slots.md │ ├── upgrading.md │ ├── validation.md │ ├── values.md │ └── vuex.md ├── package.json ├── sandbox.md ├── sponsors.md ├── validation.md └── yarn.lock ├── netlify.toml ├── package.json ├── postcss.config.js ├── release.config.js ├── src ├── components │ ├── Deselect.vue │ ├── OpenIndicator.vue │ ├── Select.vue │ └── childComponents.js ├── css │ ├── global │ │ ├── animations.css │ │ ├── component.css │ │ ├── states.css │ │ └── variables.css │ ├── modules │ │ ├── clear.css │ │ ├── dropdown-menu.css │ │ ├── dropdown-option.css │ │ ├── dropdown-toggle.css │ │ ├── open-indicator.css │ │ ├── search-input.css │ │ ├── selected.css │ │ └── spinner.css │ └── vue-select.css ├── directives │ └── appendToBody.js ├── index.js ├── mixins │ ├── ajax.js │ ├── index.js │ ├── pointerScroll.js │ └── typeAheadPointer.js ├── scss │ ├── global │ │ ├── _animations.scss │ │ ├── _component.scss │ │ ├── _states.scss │ │ └── _variables.scss │ ├── modules │ │ ├── _clear.scss │ │ ├── _dropdown-menu.scss │ │ ├── _dropdown-option.scss │ │ ├── _dropdown-toggle.scss │ │ ├── _open-indicator.scss │ │ ├── _search-input.scss │ │ ├── _selected.scss │ │ └── _spinner.scss │ └── vue-select.scss └── utility │ ├── sortAndStringify.js │ └── uniqueId.js ├── tests ├── helpers.js └── unit │ ├── .eslintrc.js │ ├── Accessibility.spec.js │ ├── Ajax.spec.js │ ├── Autoscroll.spec.js │ ├── Components.spec.js │ ├── CreateOption.spec.js │ ├── Deselecting.spec.js │ ├── Dropdown.spec.js │ ├── Filtering.spec.js │ ├── Keydown.spec.js │ ├── Labels.spec.js │ ├── Layout.spec.js │ ├── OptionComparator.spec.js │ ├── OptionKey.spec.js │ ├── ReactiveOptions.spec.js │ ├── Reduce.spec.js │ ├── Selectable.spec.js │ ├── Selecting.spec.js │ ├── Slots.spec.js │ ├── Tagging.spec.js │ ├── TypeAhead.spec.js │ └── utility │ ├── sortAndStringify.spec.js │ └── uniqueId.spec.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"], 3 | "plugins": ["@babel/plugin-transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.{js,vue}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | 18 | [*.{yml,yaml}] 19 | indent_size = 2 20 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'vue-eslint-parser', 3 | parserOptions: { 4 | parser: 'babel-eslint', 5 | sourceType: 'module', 6 | }, 7 | plugins: ['prettier'], 8 | extends: [ 9 | 'plugin:prettier/recommended', 10 | 'plugin:vue/recommended', 11 | 'prettier/vue', 12 | ], 13 | ignorePatterns: [ 14 | '!.*.js', 15 | '!docs/.vuepress', 16 | 'docs/.vuepress/dist', 17 | 'node_modules', 18 | 'dist', 19 | 'coverage', 20 | 'yarn.lock', 21 | ], 22 | } 23 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Pull Requests 2 | 3 | Looks like you want to help out on vue-select.. awesome! Here's a few things to keep in mind when contributing. 4 | 5 | - Vue Select uses semantic release to automate the release process. This means that good commit 6 | messages are critical. If you're unfamiliar with [conventional changelog](https://github.com/ajoslin/conventional-changelog) you can run `yarn commit` to generate a commit message. 7 | - It's almost always better to ask before you jump into a PR if you want to add new functionality 8 | . It's not fun for anyone when you spend time on something that doesn't end up in the component. 9 | - If your PR fixes or references an open issue, be sure to reference it in your message. 10 | - If you're adding new functionality, make sure your code has good test coverage. 11 | 12 | :tada: Thanks for contributing, and an even bigger thanks for reading these guidelines! 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [sagalbot] 2 | 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a bug report to help fix an issue with the component. 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | --- 8 | 9 | > Please respect maintainers time by filling in these sections. Your issue will likely be closed without this information. 10 | 11 | - Vue Version: 12 | - Vue Select Version: 13 | 14 | **Describe the bug** 15 | A clear and concise description of what the bug is. 16 | 17 | **Reproduction Link** 18 | A link to a reproduction of the bug. This is a huge help. 19 | 20 | **Steps To Reproduce** 21 | Outline the steps to reproduce the bug. 22 | 23 | **Expected behavior** 24 | A clear and concise description of what you expected to happen. 25 | 26 | **Screenshots** 27 | If applicable, add screenshots to help explain your problem. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discussions 4 | url: https://github.com/sagalbot/vue-select/discussions 5 | about: If you're not submitting a bug or feature request, please use discussions instead. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | release: 8 | runs-on: ubuntu-22.04 9 | steps: 10 | - uses: actions/checkout@v1 11 | - uses: actions/setup-node@v1 12 | with: 13 | node-version: 12 14 | 15 | - name: Install dependencies 16 | run: yarn install --frozen-lockfile 17 | 18 | - name: Test with Coverage 19 | run: yarn test 20 | 21 | - name: Build 22 | run: yarn build 23 | 24 | - name: Release 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 28 | run: npx semantic-release 29 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test & Build 2 | on: [pull_request] 3 | jobs: 4 | test: 5 | runs-on: ubuntu-22.04 6 | steps: 7 | - uses: actions/checkout@v1 8 | - uses: actions/setup-node@v1 9 | with: 10 | node-version: 12 11 | 12 | - name: Install dependencies 13 | run: yarn install --frozen-lockfile 14 | 15 | - name: Test with Coverage 16 | run: yarn test --coverage --coverageReporters=lcov 17 | 18 | - name: ESLint 19 | run: yarn eslint 20 | 21 | - name: Report Coverage 22 | uses: coverallsapp/github-action@master 23 | with: 24 | github-token: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | build: 27 | runs-on: ubuntu-22.04 28 | steps: 29 | - uses: actions/checkout@v1 30 | - uses: actions/setup-node@v1 31 | with: 32 | node-version: 12 33 | 34 | - name: Install dependencies 35 | run: | 36 | yarn install --frozen-lockfile 37 | cd docs 38 | yarn install --frozen-lockfile 39 | 40 | - name: Build Dist 41 | run: yarn build 42 | 43 | - name: Bundlewatch 44 | run: npx bundlewatch 45 | 46 | - name: Build Docs 47 | run: yarn build:docs 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | 4 | # local env files 5 | .env 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | *.sw* 22 | 23 | # Project specific 24 | coverage 25 | dist 26 | test/unit/coverage 27 | package-lock.json 28 | dev/dist 29 | docs/.vuepress/dist 30 | .netlify 31 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !src/**/* 3 | !dist/**/* 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | yarn.lock 4 | dist 5 | dist/* 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "proseWrap": "always" 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jeff Sagal & vue-select contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-select ![Current Release](https://img.shields.io/github/release/sagalbot/vue-select.svg?style=flat-square) ![Release Date](https://img.shields.io/github/release-date/sagalbot/vue-select?style=flat-square) ![Bundle Size](https://flat.badgen.net/bundlephobia/min/vue-select) ![Monthly Downloads](https://img.shields.io/npm/dm/vue-select.svg?style=flat-square) [![Coverage Status](https://coveralls.io/repos/github/sagalbot/vue-select/badge.svg?branch=master)](https://coveralls.io/github/sagalbot/vue-select?branch=master) ![MIT License](https://img.shields.io/github/license/sagalbot/vue-select.svg?style=flat-square) 2 | 3 | > **Everything you wish the HTML `` element could do, wrapped 13 | > up into a lightweight, extensible Vue component. 14 | 15 | Vue Select is a feature rich select/dropdown/typeahead component. It provides a default 16 | template that fits most use cases for a filterable select dropdown. The component is designed to be as 17 | lightweight as possible, while maintaining high standards for accessibility, 18 | developer experience, and customization. 19 | 20 |
21 | 22 |
23 | 24 | Vue Select aims to be as lightweight as possible, while maintaining high standards for accessibility, 25 | developer experience, and customization. Huge thanks to the [sponsors](sponsors.md) and 26 | [contributors](contributors.md) that make Vue Select possible! 27 | 28 | ## Features 29 | 30 | - Tagging 31 | - Filtering / Searching 32 | - Vuex Support 33 | - AJAX Support 34 | - SSR Support 35 | - Accessible 36 | - ~20kb Total / ~5kb CSS / ~15kb JS 37 | - Select Single/Multiple Options 38 | - Customizable with slots and SCSS variables 39 | - Zero dependencies 40 | 41 | ## Resources 42 | 43 | - **[GitHub](https://github.com/sagalbot/vue-select)** 44 | - **[CodePen Template](http://codepen.io/sagalbot/pen/NpwrQO)** 45 | -------------------------------------------------------------------------------- /docs/api/events.md: -------------------------------------------------------------------------------- 1 | ## `input` 2 | 3 | Triggered when the selected value changes. Used internally for `v-model`. 4 | 5 | ```js 6 | /** 7 | * @param {Object|String} val - selected option. 8 | */ 9 | this.$emit("input", val); 10 | ``` 11 | 12 | ## `open` 13 | 14 | Triggered when the dropdown is open. 15 | 16 | ```js 17 | this.$emit("open"); 18 | ``` 19 | 20 | ## `close` 21 | 22 | Triggered when the dropdown is closed. 23 | 24 | ```js 25 | this.$emit("close"); 26 | ``` 27 | 28 | ## `option:selecting` 29 | 30 | Triggered after an option has been selected, before updating internal state. 31 | 32 | ```js 33 | this.$emit("option:selecting", selectedOption); 34 | ``` 35 | 36 | ## `option:selected` 37 | 38 | Triggered when an option has been selected, after updating internal state. 39 | 40 | ```js 41 | this.$emit("option:selected", selectedOption); 42 | ``` 43 | 44 | ## `option:deselecting` 45 | 46 | Triggered when an option has been deselected, before updating internal state. 47 | 48 | ```js 49 | this.$emit("option:deselecting", selectedOption); 50 | ``` 51 | 52 | ## `option:deselected` 53 | 54 | Triggered when an option has been deselected, after updating internal state. 55 | 56 | ```js 57 | this.$emit("option:deselected", deselectedOption); 58 | ``` 59 | 60 | ## `option:created` 61 | 62 | Triggered when `taggable` is `true` and a new option has been created. 63 | 64 | ```js 65 | /** 66 | * @param {Object} newOption - created option 67 | */ 68 | this.$emit("option:created", newOption); 69 | ``` 70 | 71 | ## `search` 72 | 73 | Anytime the search string changes, emit the 74 | 'search' event. The event is passed with two 75 | parameters: the search string, and a function 76 | that accepts a boolean parameter to toggle the 77 | loading state. 78 | 79 | See the [AJAX Guide](/guide/ajax.html#loading-options-with-ajax) 80 | for a complete example. 81 | 82 | ```js 83 | /** 84 | * @param {String} searchString - the search string 85 | * @param {Function} toggleLoading - function to toggle loading state, accepts true or false boolean 86 | */ 87 | this.$emit('search', this.search, this.toggleLoading); 88 | ``` 89 | 90 | ```vue 91 | 92 | 98 | ``` 99 | 100 | ## `search:blur` 101 | 102 | Triggered when the text input loses focus. The dropdown will close immediately before this 103 | event is triggered. 104 | 105 | ```js 106 | this.$emit("search:blur"); 107 | ``` 108 | 109 | ## `search:focus` 110 | 111 | Triggered when the text input gains focus. The dropdown will open immediately before this 112 | event is triggered. 113 | 114 | ```js 115 | this.$emit("search:focus"); 116 | ``` 117 | -------------------------------------------------------------------------------- /docs/api/slots.md: -------------------------------------------------------------------------------- 1 | ::: tip 2 | Vue Select leverages scoped slots to allow for total customization of the presentation layer. 3 | Slots can be used to change the look and feel of the UI, or to simply swap out text. 4 | ::: 5 | 6 | 18 | 19 |
20 | 21 | ## `footer` 22 | 23 | Displayed at the bottom of the component, below `.vs__dropdown-toggle`. 24 | 25 | When implementing this slot, you'll likely need to use `appendToBody` to position the dropdown. 26 | Otherwise content in this slot will affect it's positioning. 27 | 28 | - `search {string}` - the current search query 29 | - `loading {boolean}` - is the component loading 30 | - `searching {boolean}` - is the component searching 31 | - `filteredOptions {array}` - options filtered by the search text 32 | - `deselect {function}` - function to deselect an option 33 | 34 | 35 | <<< @/.vuepress/components/SlotFooter.vue 36 | 37 | ## `header` 38 | 39 | Displayed at the top of the component, above `.vs__dropdown-toggle`. 40 | 41 | - `search {string}` - the current search query 42 | - `loading {boolean}` - is the component loading 43 | - `searching {boolean}` - is the component searching 44 | - `filteredOptions {array}` - options filtered by the search text 45 | - `deselect {function}` - function to deselect an option 46 | 47 | 48 | <<< @/.vuepress/components/SlotHeader.vue 49 | 50 | ## `list-footer` 51 | 52 | Displayed as the last item in the dropdown. No content by default. Parent element is the `
    `, 53 | so this slot should contain a root `
  • `. 54 | 55 | - `search {string}` - the current search query 56 | - `loading {boolean}` - is the component loading 57 | - `searching {boolean}` - is the component searching 58 | - `filteredOptions {array}` - options filtered by the search text 59 | 60 | 61 | <<< @/.vuepress/components/SlotListFooter.vue 62 | 63 | ## `list-header` 64 | 65 | Displayed as the first item in the dropdown. No content by default. Parent element is the `
      `, 66 | so this slot should contain a root `
    • `. 67 | 68 | - `search {string}` - the current search query 69 | - `loading {boolean}` - is the component loading 70 | - `searching {boolean}` - is the component searching 71 | - `filteredOptions {array}` - options filtered by the search text 72 | 73 | 74 | <<< @/.vuepress/components/SlotListHeader.vue 75 | 76 | ## `no-options` 77 | 78 | The no options slot is displayed above `list-footer` in the dropdown when 79 | `filteredOptions.length === 0`. 80 | 81 | - `search {string}` - the current search query 82 | - `loading {boolean}` - is the component loading 83 | - `searching {boolean}` - is the component searching 84 | 85 | 86 | <<< @/.vuepress/components/SlotNoOptions.vue 87 | 88 | ## `open-indicator` 89 | 90 | The open indicator is the caret icon on the component used to indicate dropdown status. 91 | 92 | ```js 93 | attributes: { 94 | 'ref': 'openIndicator', 95 | 'role': 'presentation', 96 | 'class': 'vs__open-indicator', 97 | } 98 | ``` 99 | 100 | 101 | <<< @/.vuepress/components/SlotOpenIndicator.vue 102 | 103 | ## `option` 104 | 105 | The current option within the dropdown, contained within `
    • `. 106 | 107 | - `option {Object}` - The currently iterated option from `filteredOptions` 108 | 109 | 110 | <<< @/.vuepress/components/SlotOption.vue 111 | 112 | ## `search` 113 | 114 | The search input has a lot of bindings, but they're grouped into `attributes` and `events`. Most 115 | of the time, you will just be binding those two with `v-on="events"` and `v-bind="attributes"`. 116 | 117 | If you want the default styling, you'll need to add `.vs__search` to the input you provide. 118 | 119 | ```js 120 | /** 121 | * Attributes to be bound to a search input. 122 | */ 123 | attributes: { 124 | 'disabled': this.disabled, 125 | 'placeholder': this.searchPlaceholder, 126 | 'tabindex': this.tabindex, 127 | 'readonly': !this.searchable, 128 | 'id': this.inputId, 129 | 'aria-autocomplete': 'list', 130 | 'aria-labelledby': `vs${this.uid}__combobox`, 131 | 'aria-controls': `vs${this.uid}__listbox`, 132 | 'aria-activedescendant': this.typeAheadPointer > -1 133 | ? `vs${this.uid}__option-${this.typeAheadPointer}` 134 | : '', 135 | 'ref': 'search', 136 | 'type': 'search', 137 | 'autocomplete': this.autocomplete, 138 | 'value': this.search, 139 | }, 140 | /** 141 | * Events that this element should handle. 142 | */ 143 | events: { 144 | 'compositionstart': () => this.isComposing = true, 145 | 'compositionend': () => this.isComposing = false, 146 | 'keydown': this.onSearchKeyDown, 147 | 'blur': this.onSearchBlur, 148 | 'focus': this.onSearchFocus, 149 | 'input': (e) => this.search = e.target.value, 150 | } 151 | ``` 152 | 153 | 154 | <<< @/.vuepress/components/SlotSearch.vue{5-6} 155 | 156 | ## `selected-option` 157 | 158 | The text displayed within `selected-option-container`. 159 | 160 | This slot doesn't exist if `selected-option-container` is implemented. 161 | 162 | - `option {Object}` - A selected option 163 | 164 | 165 | <<< @/.vuepress/components/SlotSelectedOption.vue 166 | 167 | ## `selected-option-container` 168 | 169 | This is the root element where `v-for="option in selectedValue"`. Most of the time you'll want to 170 | use `selected-option`, but this container is useful if you want to disable the deselect button, 171 | or have fine grain control over the markup. 172 | 173 | - `option {Object}` - Currently iterated selected option 174 | - `deselect {Function}` - Method used to deselect a given option when `multiple` is true 175 | - `disabled {Boolean}` - Determine if the component is disabled 176 | - `multiple {Boolean}` - If the component supports the selection of multiple values 177 | 178 | 179 | <<< @/.vuepress/components/SlotSelectedOptionContainer.vue 180 | 181 | ## `spinner` 182 | 183 | - `loading {Boolean}` - if the component is in a loading state 184 | 185 | 186 | <<< @/.vuepress/components/SlotSpinner.vue 187 | 188 |
189 | -------------------------------------------------------------------------------- /docs/contributors.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebarDepth: 0 3 | --- 4 | 5 | # Contributors 6 | 7 | Vue Select is supported by a community of awesome contributors! Without their contributions, 8 | the package would not be what it is today. 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/guide/accessibility.md: -------------------------------------------------------------------------------- 1 | Vue Select aims to follow the WAI-ARIA best practices for the 2 | [combobox](https://www.w3.org/TR/wai-aria-practices-1.1/#combobox) and 3 | [listbox](https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox) widgets. 4 | 5 | The UX of the component is designed around the HTML `` element. When `multiple` 69 | is true, `v-model` and `value` must be an array. 70 | 71 | ```html 72 | 73 | 74 | ``` 75 | 76 | 77 | 78 | ## Transforming Selections 79 | 80 | When the `options` array contains objects, vue-select returns the whole object as dropdown value 81 | upon selection. This approach makes no assumptions about the data you need, and provides a lot of 82 | flexibility. However, there will be situations where you just need to return a single key from an 83 | object. 84 | 85 | ### Returning a single key with `reduce` 86 | 87 | If you need to return a single key, or transform the selection before it is synced, vue-select 88 | provides a `reduce` callback that allows you to transform a selected option before it is passed to 89 | the `@input` event. Consider this data structure: 90 | 91 | ```js 92 | let options = [{code: 'CA', country: 'Canada'}]; 93 | ``` 94 | 95 | If we want to display the `country`, but return the `code` to `v-model`, we can use the `reduce` 96 | prop to receive only the data that's required. 97 | 98 | ```html 99 | 100 | 101 | ``` 102 | 103 | ### Deep Nested Values 104 | 105 | The `reduce` property also works well when you have a deeply nested value: 106 | 107 | ``` 108 | { 109 | country: 'canada', 110 | meta: { 111 | code: 'ca' 112 | provinces: [...], 113 | } 114 | } 115 | ``` 116 | 117 | ```html 118 | 119 | 120 | ``` 121 | 122 | 123 | 124 | ## Caveats with `reduce` 125 | 126 | The most common issue with `reduce` is when the component displays your _reduced_ _value_ instead of 127 | it's _label_. This happens when you supply Vue Select a `value` or `v-model` binding with a reduced_ 128 | value, but the complete option object is not present in the `options` array. 129 | 130 | 131 | 132 | <<< @/.vuepress/components/ReducedWithNoMatchingOption.vue 133 | 134 | In the example above, the component was supplied with an ID that doesn't exist in the `options` 135 | array. When `value` changes, Vue Select searches the supplied options, running each one 136 | through `reduce` until the corresponding option is found. When that option doesn't exist, Vue Select 137 | will end up displaying the `value` supplied. 138 | 139 | ::: warning 140 | 141 | When providing Vue Select with a _reduced_ `value` - the object that the value was reduced from must 142 | exist in the `options` array. 143 | 144 | ::: 145 | 146 | ## Tagging 147 | 148 | To allow input that's not present within the options, set the `taggable` prop to true. 149 | 150 | ```html 151 | 152 | 153 | ``` 154 | 155 | 156 | 157 | If you want added tags to be pushed to the options array, set `push-tags` to true. 158 | 159 | ```html 160 | 161 | 162 | ``` 163 | 164 | 165 | 166 | ### Using `taggable` & `reduce` together 167 | 168 | When combining `taggable` with `reduce`, you must define the `createOption` prop. The 169 | `createOption` function is responsible for defining the structure of the objects that Vue Select 170 | will create for you when adding a tag. It should return a value that has the same properties as the 171 | rest of your `options`. 172 | 173 | If you don't define `createOption`, Vue Select will construct a simple object following this 174 | structure: 175 | `{[this.label]: searchText}`. If you're using `reduce`, this is probably not what your options look 176 | like, which is why you'll need to set the function yourself. 177 | 178 | **Example** 179 | 180 | We have a taggable select for adding books to a collection. We're just concerned about getting the 181 | book title added, and our server side code will add the author details in a background process. The 182 | user has already selected a book. 183 | 184 | ```js 185 | const options = [ 186 | { 187 | title: "HTML5", 188 | author: { 189 | firstName: "Remy", 190 | lastName: "Sharp" 191 | } 192 | } 193 | ]; 194 | ``` 195 | 196 | ```html 197 | 198 | 206 | ``` 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /docs/guide/vuex.md: -------------------------------------------------------------------------------- 1 | ### Using the `input` Event with Vuex 2 | 3 | `vue-select` emits the `input` event any time the internal `value` is changed. 4 | This is the same event that allow the for the `v-model` syntax. When using 5 | Vuex for state management, you can use the `input` event to dispatch an 6 | action, or trigger a mutation. 7 | 8 | ```html 9 | 14 | ``` 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vue-select/docs", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "serve": "vuepress dev", 7 | "build": "vuepress build", 8 | "build:preview": "cross-env vuepress build" 9 | }, 10 | "devDependencies": { 11 | "@octokit/graphql": "^4.3.1", 12 | "@popperjs/core": "^2.1.0", 13 | "@vuepress/plugin-active-header-links": "^1.4.0", 14 | "@vuepress/plugin-nprogress": "^1.4.0", 15 | "@vuepress/plugin-pwa": "^1.4.0", 16 | "@vuepress/plugin-register-components": "^1.4.0", 17 | "@vuepress/plugin-search": "^1.4.0", 18 | "axios": "^0.19.2", 19 | "cross-env": "^7.0.2", 20 | "date-fns": "^2.11.0", 21 | "dotenv": "^8.2.0", 22 | "fuse.js": "^6.4.0", 23 | "gh-pages": "^2.2.0", 24 | "octonode": "^0.9.5", 25 | "vue": "^2.6.10", 26 | "vuepress": "^1.4.0", 27 | "vuepress-plugin-sitemap": "^2.3.1", 28 | "vuex": "^3.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/sandbox.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar: false 3 | editLink: false 4 | layout: Sandbox 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /docs/sponsors.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebarDepth: 0 3 | --- 4 | 5 | ## Springloaded 6 | 7 | Vue Select is now being directly supported by [Springloaded](https://springloaded.co?ref=vue-select) 🎉, a software 8 | agency founded by [Owen Conti](https://github.com/owenconti) 9 | and [Jeff Sagal](https://github.com/sagalbot) - the maintainer of Vue Select. 10 | 11 | With support from Springloaded, we'll be able to dedicate more time to improving Vue Select and providing better support for the community. 12 | 13 | ## Sponsors 14 | 15 | Huge thanks to the sponsors that help make Vue Select possible! Interested in providing your support? [Become a sponsor!](https://github.com/sponsors/sagalbot). 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/validation.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | # Settings in the [build] context are global and are applied to all contexts 2 | # unless otherwise overridden by more specific contexts. 3 | # @see https://www.netlify.com/docs/netlify-toml-reference/ 4 | [build] 5 | base = "docs" 6 | publish = "docs/.vuepress/dist" 7 | command = "yarn build" 8 | 9 | # Deploy Preview context 10 | # 11 | # All deploys resulting from a pull/merge request will 12 | # inherit these settings. 13 | [context.deploy-preview] 14 | command = "yarn build:preview" 15 | 16 | # Branch Deploy context: all deploys that are not from a pull/merge request or 17 | # from the Production branch will inherit these settings. 18 | [context.branch-deploy] 19 | command = "yarn build:preview" 20 | 21 | # Redirects and headers are GLOBAL for all builds – they do not get scoped to 22 | # contexts no matter where you define them in the file. 23 | [[redirects]] 24 | from = "/guide/templating.html" 25 | to = "/guide/slots.html" 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-select", 3 | "version": "3.20.4", 4 | "description": "Everything you wish the HTML