mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-16 09:10:33 +03:00
nuxt setup, tailwind
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
Vue Select aims to follow the WAI-ARIA best practices for the
|
||||
[combobox](https://www.w3.org/TR/wai-aria-practices-1.1/#combobox) and
|
||||
[listbox](https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox) widgets.
|
||||
|
||||
The UX of the component is designed around the HTML `<select>` element, while following the WAI-ARIA
|
||||
specifications and best practices for creating accessible components.
|
||||
|
||||
## Combobox
|
||||
|
||||
- [WAI-ARIA Combobox - Best Practices](https://www.w3.org/TR/wai-aria-practices-1.1/#combobox)
|
||||
- [WAI-ARIA Combobox - Specification](https://www.w3.org/TR/wai-aria-1.1/#combobox)
|
||||
|
||||
## Listbox
|
||||
|
||||
- [WAI-ARIA Listbox - Best Practices](https://www.w3.org/TR/wai-aria-practices-1.1/#Listbox)
|
||||
|
||||
### Autocomplete
|
||||
|
||||
WAI-ARIA suggests four forms of autocomplete for Comboboxes. Vue Select can be configured to provide
|
||||
these use cases.
|
||||
|
||||
1. **No autocomplete**
|
||||
|
||||
> When the popup is triggered, the suggested values it contains are the same regardless of the
|
||||
characters typed in the textbox.
|
||||
|
||||
```html
|
||||
<v-select :filterable="false" :options="['No Autocomplete', 'List Autocomplete']" />
|
||||
```
|
||||
<v-select :filterable="false" :options="['No Autocomplete', 'List Autocomplete']" />
|
||||
|
||||
2. **List autocomplete with manual selection**
|
||||
|
||||
> When the popup is triggered, it presents suggested values that complete or logically
|
||||
correspond to the characters typed in the textbox. The character string the user has
|
||||
typed will become the value of the textbox unless the user selects a value in the popup.
|
||||
|
||||
```html
|
||||
<v-select taggable :options="['No Autocomplete', 'List Autocomplete']" />
|
||||
```
|
||||
<v-select taggable :options="['No Autocomplete', 'List Autocomplete']" />
|
||||
|
||||
3. **List autocomplete with automatic selection**
|
||||
|
||||
> When the popup is triggered, it presents suggested values that complete or logically
|
||||
correspond to the characters typed in the textbox, and the first suggestion is automatically
|
||||
highlighted as selected. The automatically selected suggestion becomes the value of the textbox
|
||||
when the combobox loses focus unless the user chooses a different suggestion or changes the
|
||||
character string in the textbox.
|
||||
|
||||
```html
|
||||
<v-select :options="['No Autocomplete', 'List Autocomplete']" />
|
||||
```
|
||||
<v-select :options="['No Autocomplete', 'List Autocomplete']" />
|
||||
|
||||
4. **List with inline autocomplete**
|
||||
|
||||
> This is the same as list with automatic selection with one additional feature. The portion of
|
||||
the selected suggestion that has not been typed by the user, a completion string, appears inline
|
||||
after the input cursor in the textbox. The inline completion string is visually highlighted and
|
||||
has a selected state.
|
||||
|
||||
🚧 Vue Select does not yet support this configuration, but it is on the roadmap
|
||||
[#865](https://github.com/sagalbot/vue-select/issues/865). 🚧
|
||||
@@ -0,0 +1,72 @@
|
||||
## Loading Options with AJAX
|
||||
|
||||
The `search` event provides a hook to load options from a parent component
|
||||
when the search text is updated. It is emitted with two parameters:
|
||||
|
||||
**Search Event Parameters**
|
||||
- `search {String}` The current search string
|
||||
- `loading {Function}` Accepts a boolean parameter to toggle the loading state
|
||||
|
||||
```html
|
||||
<v-select @search="fetchOptions" />
|
||||
```
|
||||
|
||||
```js
|
||||
/**
|
||||
* Triggered when the search text changes.
|
||||
*
|
||||
* @param search {String} Current search text
|
||||
* @param loading {Function} Toggle loading class
|
||||
*/
|
||||
fetchOptions (search, loading) {
|
||||
// ... do some asynchronous stuff!
|
||||
},
|
||||
```
|
||||
|
||||
The `loading` function accepts a boolean parameter that will be assigned
|
||||
to the vue-select internal `loading` property. Call `loading(true)` to set the
|
||||
`loading` property to `true` - toggling the loading spinner. After your
|
||||
asynchronous operation completes, call `loading(false)` to toggle it off.
|
||||
|
||||
## Disabling Filtering
|
||||
|
||||
When loading server side options, it can be useful to disable the
|
||||
client side filtering. Use the `filterable` prop to disable filtering.
|
||||
|
||||
```js
|
||||
/**
|
||||
* When true, existing options will be filtered
|
||||
* by the search text. Should not be used in
|
||||
* conjunction with taggable.
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
```
|
||||
|
||||
## Loading Spinner
|
||||
|
||||
Vue Select includes a default loading spinner that appears when the loading class is present. The
|
||||
`spinner` slot allows you to implement your own spinner.
|
||||
|
||||
```html
|
||||
<div class="spinner" v-show="spinner">Loading...</div>
|
||||
```
|
||||
|
||||
## Library Agnostic
|
||||
|
||||
Since Vue.js does not ship with ajax functionality as part of the core library, it's up to you to
|
||||
process the ajax requests in your parent component.
|
||||
|
||||
I recommend using [axios](https://github.com/axios/axios) for creating your applications HTTP layer,
|
||||
or [`fetch()`](https://github.com/github/fetch) for simple requests.
|
||||
|
||||
## Example
|
||||
|
||||
The [codepen example](https://codepen.io/sagalbot/pen/POMeOX) wraps up all the above concepts and
|
||||
searches GitHub repositories. It also uses scoped slots to add some custom templating.
|
||||
|
||||
<CodePen url="POMeOX" height="400"/>
|
||||
@@ -0,0 +1,83 @@
|
||||
### Prop: `components` `{Object}`
|
||||
---
|
||||
|
||||
Vue Select utilizes child components throughout, and exposes an API to overwrite these components
|
||||
with your own, using the `components` `{Object}` prop. The object provided to the `components` prop
|
||||
will be merged with Vue Select's default components.
|
||||
|
||||
<<< @/../src/components/childComponents.js{4-7}
|
||||
|
||||
You can override the value of any of these keys with your own components.
|
||||
|
||||
## Deselect <Badge text="v3.1.0+" />
|
||||
|
||||
You may wish to roll your own deselect button. `Deselect` is used within tags on
|
||||
`multiple` selects, and serves as the clear button for single selects. Maybe you just want to use
|
||||
a simple `<button>Clear</button>` instead.
|
||||
|
||||
```html
|
||||
<v-select :components="{Deselect}" />
|
||||
```
|
||||
|
||||
```js
|
||||
export default {
|
||||
data: () => ({
|
||||
Deselect: {
|
||||
render: createElement => createElement('span', '❌'),
|
||||
},
|
||||
}),
|
||||
};
|
||||
```
|
||||
|
||||
<ClearButtonOverride />
|
||||
|
||||
The same approach applies for `multiple` selects:
|
||||
|
||||
<MultipleClearButtonOverride />
|
||||
|
||||
## OpenIndicator <Badge text="v3.1.0+" />
|
||||
|
||||
The `OpenIndicator` component is the 'caret' used within the component that adjusts orientation
|
||||
based on whether the dropdown is open or closed.
|
||||
|
||||
```html
|
||||
<v-select :components="{OpenIndicator}" />
|
||||
```
|
||||
```js
|
||||
export default {
|
||||
data: () => ({
|
||||
selected: ['Canada'],
|
||||
OpenIndicator: {
|
||||
render: createElement => createElement('span', {class: {'toggle': true}}),
|
||||
},
|
||||
}),
|
||||
};
|
||||
```
|
||||
|
||||
<OpenIndicatorOverride />
|
||||
|
||||
## Setting Globally at Registration
|
||||
|
||||
If you want all instances of Vue Select to use your custom components throughout your app, while
|
||||
only having to set the implementation once, you can do so when registering Vue Select as a component.
|
||||
|
||||
```js
|
||||
import Vue from 'vue';
|
||||
import vSelect from 'vue-select';
|
||||
|
||||
// Set the components prop default to return our fresh components
|
||||
vSelect.props.components.default = () => ({
|
||||
Deselect: {
|
||||
render: createElement => createElement('span', '❌'),
|
||||
},
|
||||
OpenIndicator: {
|
||||
render: createElement => createElement('span', '🔽'),
|
||||
},
|
||||
});
|
||||
|
||||
// Register the component
|
||||
Vue.component(vSelect)
|
||||
```
|
||||
|
||||
<CustomComponentRegistration />
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
Vue Select offers many APIs for customizing the look and feel from the component. You can use
|
||||
[scoped slots](../api/slots.md), [custom child components](components.md), or modify the built in
|
||||
SCSS variables.
|
||||
|
||||
::: tip
|
||||
Support for CSS variables (custom properties) is currently on the road map for those
|
||||
that are not using sass in their projects.
|
||||
:::
|
||||
|
||||
## SCSS Variables
|
||||
|
||||
Variables are leveraged in as much of the component styles as possible. If you really want to dig
|
||||
into the SCSS, the files are located in `src/scss`. The variables listed below can be found at
|
||||
[`src/scss/global/_variables`](https://github.com/sagalbot/vue-select/blob/master/src/scss/global/_variables.scss).
|
||||
|
||||
All variables are implemented with `!default` in order to make them easier to override in your
|
||||
application.
|
||||
|
||||
<<< @/../src/scss/global/_variables.scss
|
||||
|
||||
## Overriding Default Styles
|
||||
|
||||
Vue Select takes the approach of using selectors with a single level of specificity, while using
|
||||
classes that are very specific to Vue Select to avoid collisions with your app.
|
||||
|
||||
All classes within Vue Select use the `vs__` prefix, and selectors are generally a single classname
|
||||
– unless there is a state being applied to the component.
|
||||
|
||||
In order to override a default property in your app, you should add one level of specificity.
|
||||
The easiest way to do this, is to add `.v-select` before the `vs__*` selector if you want to adjust
|
||||
all instances of Vue Select, or add your own classname if you just want to affect one.
|
||||
|
||||
<CssSpecificity />
|
||||
|
||||
<<< @/.vuepress/components/CssSpecificity.vue
|
||||
|
||||
## Dropdown Transition
|
||||
|
||||
By default, the dropdown transitions with a `.15s` cubic-bezier opacity fade in/out. The component
|
||||
uses the [VueJS transition system](https://vuejs.org/v2/guide/transitions.html). By default, the
|
||||
transition name is `vs__fade`. There's a couple ways to override or change this transition.
|
||||
|
||||
1. Use the `transition` prop. Applying this prop will change the name of the animation classes and
|
||||
negate the default CSS. If you want to remove it entirely, you can set it to an empty string.
|
||||
|
||||
```html
|
||||
<v-select transition="" />
|
||||
```
|
||||
|
||||
2. You can also override the default CSS for the `vs__fade` transition. Again, if you
|
||||
wanted to eliminate the transition entirely:
|
||||
|
||||
```css
|
||||
.vs__fade-enter-active,
|
||||
.vs__fade-leave-active {
|
||||
transition: none;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,4 @@
|
||||
### Codepen Collection
|
||||
|
||||
I've put together a collection of examples, including all the examples
|
||||
from this documentation site on [Codepen](https://codepen.io/collection/nrkgxV/#).
|
||||
@@ -0,0 +1,19 @@
|
||||
Vue Select provides two props accepting `functions` that can be used to implement custom filtering
|
||||
algorithms.
|
||||
|
||||
- `filter` <Badge text="v2.5.0+" />
|
||||
- `filterBy` <Badge text="v2.5.0+" />
|
||||
|
||||
By default, the component will perform a very basic check to see if an options label includes
|
||||
the current search text. If you're using scoped slots, you might have information within the
|
||||
option templates that should be searchable. Or maybe you just want a better search algorithm that
|
||||
can do fuzzy search matching.
|
||||
|
||||
## Filtering with Fuse.js
|
||||
|
||||
You can use the `filter` and `filterBy` props to hook right into something like
|
||||
[Fuse.js](https://fusejs.io/) that can handle searching multiple object keys with fuzzy matchings.
|
||||
|
||||
<FuseFilter />
|
||||
|
||||
<<< @/.vuepress/components/FuseFilter.vue
|
||||
@@ -0,0 +1,23 @@
|
||||
Vue Select doesn't ship with first party support for infinite scroll, but it's possible to implement
|
||||
by hooking into the `open`, `close`, and `search` events, along with the `filterable` prop, and the
|
||||
`list-footer` slot.
|
||||
|
||||
Let's break down the example below, starting with the `data`.
|
||||
|
||||
- `observer` - a new `IntersectionObserver` with `infiniteScroll` set as the callback
|
||||
- `limit` - the number of options to display
|
||||
- `search` - since we've disabled Vue Selects filtering, we'll need to filter options ourselves
|
||||
|
||||
When Vue Select opens, the `open` event is emitted and `onOpen` will be called. We wait for
|
||||
`$nextTick()` so that the `$ref` we need will exist, then begin observing it for intersection.
|
||||
|
||||
The observer is set to call `infiniteScroll` when the `<li>` is completely visible within the list.
|
||||
Some fancy destructuring is done here to get the first `ObservedEntry`, and specifically the
|
||||
`isIntersecting` & `target` properties. If the `<li>` is intersecting, we increase the `limit`, and
|
||||
ensure that the scroll position remains where it was before the list size changed. Again, it's
|
||||
important to wait for `$nextTick` here so that the DOM elements have been inserted before setting
|
||||
the scroll position.
|
||||
|
||||
<InfiniteScroll />
|
||||
|
||||
<<< @/.vuepress/components/InfiniteScroll.vue
|
||||
@@ -0,0 +1,60 @@
|
||||
## Yarn / NPM
|
||||
Install with yarn:
|
||||
```bash
|
||||
yarn add vue-select
|
||||
|
||||
# or, using NPM
|
||||
npm install vue-select
|
||||
```
|
||||
|
||||
Then, import and register the component:
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import vSelect from 'vue-select'
|
||||
|
||||
Vue.component('v-select', vSelect)
|
||||
```
|
||||
|
||||
The component itself does not include any CSS. You'll need to include it separately:
|
||||
|
||||
```js
|
||||
import 'vue-select/dist/vue-select.css';
|
||||
```
|
||||
|
||||
Alternatively, you can import the scss for complete control of the component styles:
|
||||
|
||||
```scss
|
||||
@import "vue-select/src/scss/vue-select.scss";
|
||||
```
|
||||
|
||||
## In the Browser
|
||||
|
||||
vue-select ships as an UMD module that is accessible in the browser. When loaded
|
||||
in the browser, you can access the component through the `VueSelect.VueSelect`
|
||||
global variable. You'll need to load Vue.js, vue-select JS & vue-select CSS.
|
||||
|
||||
```html
|
||||
<!-- include VueJS first -->
|
||||
<script src="https://unpkg.com/vue@latest"></script>
|
||||
|
||||
<!-- use the latest vue-select release -->
|
||||
<script src="https://unpkg.com/vue-select@latest"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/vue-select@latest/dist/vue-select.css">
|
||||
|
||||
<!-- or point to a specific vue-select release -->
|
||||
<script src="https://unpkg.com/vue-select@3.0.0"></script>
|
||||
<link rel="stylesheet" href="https://unpkg.com/vue-select@3.0.0/dist/vue-select.css">
|
||||
```
|
||||
Then register the component in your javascript:
|
||||
|
||||
```js
|
||||
Vue.component('v-select', VueSelect.VueSelect);
|
||||
```
|
||||
|
||||
<CodePen url="dJjzeP" />
|
||||
|
||||
## Vue Compatibility
|
||||
|
||||
- If you're on Vue `1.x`, use vue-select `1.x`.
|
||||
- The `1.x` branch has not received updates since the 2.0 release.
|
||||
@@ -0,0 +1,73 @@
|
||||
### Customizing Keydown Behaviour
|
||||
---
|
||||
|
||||
## selectOnKeyCodes <Badge text="v3.3.0+" />
|
||||
|
||||
`selectOnKeyCodes {Array}` is an array of keyCodes that will trigger a typeAheadSelect. Any keyCodes
|
||||
in this array will prevent the default event action and trigger a typeahead select. By default,
|
||||
it's just `[13]` for return. For example, maybe you want to tag on a comma keystroke:
|
||||
|
||||
<TagOnComma />
|
||||
|
||||
<<< @/.vuepress/components/TagOnComma.vue
|
||||
|
||||
## mapKeyDown <Badge text="v3.3.0+" />
|
||||
|
||||
Vue Select provides the `map-keydown` Function prop to allow for customizing the components response to
|
||||
keydown events while the search input has focus.
|
||||
|
||||
```js
|
||||
/**
|
||||
* @param map {Object} Mapped keyCode to handlers { <keyCode>:<callback> }
|
||||
* @param vm {VueSelect}
|
||||
* @return {Object}
|
||||
*/
|
||||
(map, vm) => map,
|
||||
```
|
||||
|
||||
By default, the prop is a no–op returning the same object `map` object it receives. This object
|
||||
maps keyCodes to handlers: `{ <keyCode>: <callback> }`. Modifying this object can override default
|
||||
functionality, or add handlers for different keys that the component doesn't normally listen for.
|
||||
|
||||
Note that any keyCodes you've added to `selectOnKeyCodes` will be passed to `map-keydown` as well,
|
||||
so `map-keydown` will always take precedence.
|
||||
|
||||
**Default Handlers**
|
||||
|
||||
```js
|
||||
// delete
|
||||
8: e => this.maybeDeleteValue()
|
||||
|
||||
// tab
|
||||
9: e => this.onTab()
|
||||
|
||||
// enter
|
||||
13: e => {
|
||||
e.preventDefault();
|
||||
return this.typeAheadSelect();
|
||||
}
|
||||
|
||||
// esc
|
||||
27: e => this.onEscape()
|
||||
|
||||
// up
|
||||
38: e => {
|
||||
e.preventDefault();
|
||||
return this.typeAheadUp();
|
||||
}
|
||||
|
||||
// down
|
||||
40: e => {
|
||||
e.preventDefault();
|
||||
return this.typeAheadDown();
|
||||
}
|
||||
```
|
||||
|
||||
### Example: Autocomplete Email Addresses
|
||||
|
||||
This is example listens for the `@` key, and autocompletes an email address with `@gmail.com`.
|
||||
|
||||
<CustomHandlers />
|
||||
|
||||
<<< @/.vuepress/components/CustomHandlers.vue
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
## Right to Left
|
||||
|
||||
Vue Select supports RTL using the standard HTML API using the `dir` prop.
|
||||
|
||||
```html
|
||||
<v-select dir="rtl"></v-select>
|
||||
```
|
||||
|
||||
The `dir` prop accepts the same values as the [HTML spec](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir):
|
||||
|
||||
- `rtl`
|
||||
- `ltr`
|
||||
- `auto`
|
||||
|
||||
## Component Text
|
||||
|
||||
All of the text within the component has been wrapped within [slots](https://vuejs.org/v2/guide/components.html#Content-Distribution-with-Slots) and can be replaced in your app.
|
||||
|
||||
### Loading Spinner
|
||||
*Slot Definition:*
|
||||
```html
|
||||
<slot name="spinner">
|
||||
<div class="spinner" v-show="mutableLoading">Loading...</div>
|
||||
</slot>
|
||||
```
|
||||
*Implementation:*
|
||||
```html
|
||||
<v-select>
|
||||
<i slot="spinner" class="icon icon-spinner"></i>
|
||||
</v-select>
|
||||
```
|
||||
|
||||
### No Options Text
|
||||
*Slot Definition:*
|
||||
```html
|
||||
<slot name="no-options">Sorry, no matching options.</slot>
|
||||
```
|
||||
*Implementation:*
|
||||
```html
|
||||
<v-select>
|
||||
<div slot="no-options">No Options Here!</div>
|
||||
</v-select>
|
||||
```
|
||||
|
||||
For a full list of component slots, view the [slots API docs](../api/slots.md).
|
||||
@@ -0,0 +1,17 @@
|
||||
### Using Vue Select in v-for Loops
|
||||
---
|
||||
|
||||
There may be times that you are including Vue Select within loops of data, such as a table. This can
|
||||
pose some challenges when emitting events from the component, as you won't know which Vue Select
|
||||
instance emitted it. This can make it difficult to wire up with things like Vuex.
|
||||
|
||||
Fortunately, you can solve this problem with an anonymous function. The example below doesn't use
|
||||
Vuex just to keep things succinct, but the same solution would apply. The `@input` is handled
|
||||
with an inline anonymous function, allowing the selected country to be passed to the `updateCountry`
|
||||
method with the `country` and the `person` object.
|
||||
|
||||
<LoopedSelect />
|
||||
|
||||
<<< @/.vuepress/components/LoopedSelect.vue
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
## Options Prop
|
||||
|
||||
`vue-select` accepts arrays of primitive values or objects to use as options through the `options` prop:
|
||||
|
||||
```html
|
||||
<!-- array of strings or numbers -->
|
||||
<v-select :options="['Canada', 'United States']"></v-select>
|
||||
```
|
||||
|
||||
<v-select :options="['Canada', 'United States']"></v-select>
|
||||
|
||||
```html
|
||||
<!-- or, an array of objects -->
|
||||
<v-select :options="[{label: 'Canada', code: 'ca'}]"></v-select>
|
||||
```
|
||||
|
||||
<v-select :options="[{label: 'Canada', code: 'ca'}]"></v-select>
|
||||
|
||||
## Option Labels
|
||||
|
||||
#### Options as Primitives (strings, numbers, boolean)
|
||||
|
||||
When `options` contains strings or numbers, they'll be used as the label for the option within the
|
||||
component. No further configuration is necessary.
|
||||
|
||||
#### Options as Objects
|
||||
|
||||
When `options` is an array of objects, the component must generate a label to be shown as the
|
||||
options text. By default, `vue-select` will attempt to render `option.label` as the option label.
|
||||
You might not have a `label` key in your objects, so you can set your own label to match your
|
||||
source data using the `label {String}` prop.
|
||||
|
||||
For example, consider an object with `countryCode` and `countryName` properties:
|
||||
|
||||
```json
|
||||
{
|
||||
countryCode: "CA",
|
||||
countryName: "Canada"
|
||||
}
|
||||
```
|
||||
|
||||
If you wanted to display `Canada` in the dropdown, you'd use the `countryName` key:
|
||||
|
||||
```html
|
||||
<v-select label="countryName" :options="countries"></v-select>
|
||||
```
|
||||
|
||||
<country-select />
|
||||
|
||||
## Null / Empty Options
|
||||
|
||||
`vue-select` requires the `options` prop to be an `array`. If you are using Vue in development
|
||||
mode, you will get warnings attempting to pass anything other than an `array` to the `options` prop.
|
||||
If you need a `null`/`empty` value, use an empty array `[]`.
|
||||
@@ -0,0 +1,18 @@
|
||||
::: tip <Badge text="3.8.0+" />
|
||||
Pagination is supported using slots available with Vue Select 3.8 and above.
|
||||
:::
|
||||
|
||||
Pagination can be a super helpful tool when working with large sets of data. If you have 1,000
|
||||
options, the component is going to render 1,000 DOM nodes. That's a lot of nodes to insert/remove,
|
||||
and chances are your user is only interested in a few of them anyways.
|
||||
|
||||
To implement pagination with Vue Select, you can take advantage of the `list-footer` slot. It
|
||||
appears below all other options in the drop down list.
|
||||
|
||||
To make pagination work properly with filtering, you'll have to handle it yourself in the parent.
|
||||
You can use the `filterable` boolean to turn off Vue Select's filtering, and then hook into the
|
||||
`search` event to use the current search query in the parent component.
|
||||
|
||||
<Paginated />
|
||||
|
||||
<<< @/.vuepress/components/Paginated.vue
|
||||
@@ -0,0 +1,33 @@
|
||||
## Default
|
||||
|
||||
With the default CSS, Vue Select uses absolute positioning to render the dropdown menu. The root
|
||||
`.v-select` container (the components `$el`) is used as the `relative` parent for the dropdown. The
|
||||
dropdown will be displayed below the `$el` regardless of the available space.
|
||||
|
||||
This works for most cases, but you might run into issues placing into a modal or near the bottom of
|
||||
the viewport. If you need more fine grain control, you can use calculated positioning.
|
||||
|
||||
## Calculated <Badge text="v3.7.0+" />
|
||||
|
||||
If you want more control over how the dropdown is rendered, or if you're running into z-index issues,
|
||||
you may use the `appendToBody` boolean prop. When enabled, Vue Select will append the dropdown to
|
||||
the document, outside of the `.v-select` container, and position it with Javscript.
|
||||
|
||||
When `appendToBody` is true, the positioning will be handled by the `calculatePosition` prop. This
|
||||
function is responsible for setting top/left absolute positioning values for the dropdown. The
|
||||
default implementation places the dropdown in the same position that it would normally appear.
|
||||
|
||||
## Popper.js Integration <Badge text="v3.7.0+" />
|
||||
|
||||
[Popper.js](https://popper.js.org/) is an awesome, 3kb utility for calculating positions of just
|
||||
about any DOM element relative to another.
|
||||
|
||||
By using the `appendToBody` and `calculatePosition` props, we're able to integrate directly with
|
||||
popper to calculate positioning for us.
|
||||
|
||||
<PositionedWithPopper />
|
||||
|
||||
Check out the [Popper Docs](https://popper.js.org/docs/v2/modifiers/) to see the full `modifiers`
|
||||
API being used below.
|
||||
|
||||
<<< @/.vuepress/components/PositionedWithPopper.vue{25-59}
|
||||
@@ -0,0 +1,44 @@
|
||||
## Selectable Prop <Badge text="v3.3.0+" />
|
||||
|
||||
The `selectable` prop determines if an option is selectable or not. If `selectable` returns false
|
||||
for a given option, it will be displayed with a `vs__dropdown-option--disabled` class. The option
|
||||
will be disabled and unable to be selected.
|
||||
|
||||
```js
|
||||
selectable: {
|
||||
type: Function,
|
||||
/**
|
||||
* @param {Object|String} option
|
||||
* @return {boolean}
|
||||
*/
|
||||
default: option => true,
|
||||
},
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Here `selectable` is used to prevent books by a certain author from being chosen. In this case,
|
||||
the options passed to the component are objects:
|
||||
|
||||
```json
|
||||
{
|
||||
title: "Right Ho Jeeves",
|
||||
author: { firstName: "P.D", lastName: "Woodhouse" },
|
||||
}
|
||||
```
|
||||
|
||||
This object will be passed to `selectable`, so we can check if the author should be selectable or not.
|
||||
|
||||
<UnselectableExample />
|
||||
|
||||
<<< @/.vuepress/components/UnselectableExample.vue{6}
|
||||
|
||||
## Limiting the Number of Selections
|
||||
|
||||
`selectable` can also be used a bit more creatively to limit the number selections that can be made
|
||||
within the component. In this case, the user can select any author, but may only select a maximum
|
||||
of three books.
|
||||
|
||||
<LimitSelectionQuantity />
|
||||
|
||||
<<< @/.vuepress/components/LimitSelectionQuantity.vue{8}
|
||||
@@ -0,0 +1,32 @@
|
||||
::: tip 🚧
|
||||
This section of the guide is a work in progress! Check back soon for an update.
|
||||
Vue Select currently offers quite a few scoped slots, and you can check out the
|
||||
[API Docs for Slots](../api/slots.md) in the meantime while a good guide is put together.
|
||||
:::
|
||||
|
||||
### Scoped Slot `option`
|
||||
|
||||
vue-select provides the scoped `option` slot in order to create custom dropdown templates.
|
||||
|
||||
```html
|
||||
<v-select :options="options" label="title">
|
||||
<template v-slot:option="option">
|
||||
<span :class="option.icon"></span>
|
||||
{{ option.title }}
|
||||
</template>
|
||||
</v-select>
|
||||
```
|
||||
|
||||
Using the `option` slot with props `"option"` provides the current option variable to the template.
|
||||
|
||||
<CodePen url="NXBwYG" height="500"/>
|
||||
|
||||
### Improving the default `no-options` text
|
||||
|
||||
The `no-options` slot is displayed in the dropdown when `filteredOptions === 0`. By default, it
|
||||
displays _Sorry, no matching options_. You can add more contextual information by using the slot
|
||||
in your own apps.
|
||||
|
||||
<BetterNoOptions />
|
||||
|
||||
<<< @/.vuepress/components/BetterNoOptions.vue
|
||||
@@ -0,0 +1,119 @@
|
||||
## `index` prop replaced with `reduce`
|
||||
|
||||
- v2.x provided the `index` `{String}` prop to return a single key from a selected object
|
||||
- v3.x removes the `index` prop, replacing it with the `reduce` `{Function}` prop.
|
||||
|
||||
Using a function instead of a string provides a whole lot more flexibility, allowing for things like
|
||||
deeply nested values, and really cleaned up the code internally.
|
||||
|
||||
```js
|
||||
const options = [{country: 'Canada', code: 'CA'},];
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- v2: using index --->
|
||||
<v-select :options="options" label="country" index="code" />
|
||||
|
||||
<!-- v3: using reduce --->
|
||||
<v-select :options="options" label="country" :reduce="country => country.code" />
|
||||
```
|
||||
|
||||
View the full [documentation for `reduce`](values.md#returning-a-single-key-with-reduce).
|
||||
|
||||
## Events instead of Callbacks
|
||||
|
||||
Three function callbacks have been removed in favor of using events.
|
||||
|
||||
- `onChange`
|
||||
- `onInput`
|
||||
- `onSearch`
|
||||
|
||||
While this is a breaking change, the change in your application should be as simple as swapping the
|
||||
prop you were using for an event.
|
||||
|
||||
### `onChange` & `onInput`
|
||||
|
||||
In v2.x, Overwriting `onChange` in an application was more likely to break vue-select's internals
|
||||
and cause issues. The `input` event provides identical functionality and can be swapped out in your
|
||||
application.
|
||||
|
||||
```html
|
||||
<!-- version 2: -->
|
||||
<v-select :on-change="doSomething" />
|
||||
|
||||
<!-- version 3: -->
|
||||
<v-select @input="doSomething" />
|
||||
```
|
||||
|
||||
Additionally, the `change` event has been removed. This event was redundant, `input` should be used
|
||||
instead.
|
||||
|
||||
```html
|
||||
<!-- version 2: -->
|
||||
<v-select @change="doSomething" />
|
||||
|
||||
<!-- version 3: -->
|
||||
<v-select @input="doSomething" />
|
||||
```
|
||||
|
||||
### `onSearch`
|
||||
|
||||
The `onSearch` prop was removed for the same reason as `onChange` and `onInput`. The `search` event
|
||||
has always provided the same parameters and can be used in it's place.
|
||||
|
||||
```html
|
||||
<!-- version 2: -->
|
||||
<v-select :on-search="doSomeAjax" />
|
||||
|
||||
<!-- version 3: -->
|
||||
<v-select @search="doSomeAjax" />
|
||||
```
|
||||
|
||||
### `@search` with null search string
|
||||
|
||||
The `@search` event is now fired anytime the search string changes. In v2.x, the component
|
||||
would first check if the search string was empty, and only emit the event if it had at least one
|
||||
character. This was a design mistake, as it should be the consumers decision if a search should be
|
||||
run on an empty string.
|
||||
|
||||
## Separated CSS
|
||||
|
||||
CSS was removed from the JS bundle in favor of a separate CSS file to support SSR and easier
|
||||
customization.
|
||||
|
||||
```js
|
||||
@import vSelect from 'vue-select`;
|
||||
@import 'vue-select/dist/vue-select.css';
|
||||
```
|
||||
|
||||
## New Class Selector Prefix
|
||||
|
||||
In order to avoid CSS collisions and allow for low specificity overrides of CSS, all classes have
|
||||
been renamed to include the `vs__` prefix. The full list of renamed classes are listed below:
|
||||
|
||||
| original | renamed |
|
||||
| ------- | --------- |
|
||||
| `.open-indicator` | `.vs__open-indicator` |
|
||||
| `.dropdown-toggle` | `.vs__dropdown-toggle` |
|
||||
| `.dropdown-menu` | `.vs__dropdown-menu` |
|
||||
| `.clear` | `.vs__clear` |
|
||||
| `.selected-tag` | `.vs__selected` |
|
||||
| `.no-options` | `.vs__no-options` |
|
||||
| `.spinner` | `.vs__spinner` |
|
||||
| `.close` | `.vs__deselect` |
|
||||
| `.active` | `.vs__active` |
|
||||
|
||||
## Internal State
|
||||
|
||||
**The changes listed below are very unlikely to break your apps** unless you've been hooking into
|
||||
vue-select internal values. [#781](https://github.com/sagalbot/vue-select/pull/781)
|
||||
(thanks [@owenconti!](https://github.com/owenconti)) introduced a number of optimizations to the
|
||||
way that the component handles internal state.
|
||||
|
||||
- `value`: the `value` prop is undefined by default. vue-select no longer maintains an internal `mutableValue` state when a `value` prop has been passed. When `:value` or `v-model` is not used, vue-select will maintain internal state using the `_value` property.
|
||||
- `mutableOptions` has been removed in favor of an `optionList` computed property.
|
||||
|
||||
## Misc
|
||||
|
||||
- `fade` transition renamed to `vs__fade`
|
||||
- Removed `a` element that was serving as the click handler within dropdown options
|
||||
@@ -0,0 +1,24 @@
|
||||
## Required
|
||||
|
||||
If you need to ensure that a selection is made before a form is submitted, you can
|
||||
use the `required` attribute in combination with the `search` scoped slot in order
|
||||
to do so.
|
||||
|
||||
However, the `search` input within the component does not actually store a value, so
|
||||
simply adding the `required` attribute won't work. Instead, we'll bind the attribute
|
||||
dynamically, so that it's only present if we don't have a selection.
|
||||
|
||||
<ValidationRequired />
|
||||
|
||||
```html
|
||||
<v-select :options="books" label="title" v-model="selected">
|
||||
<template #search="{attributes, events}">
|
||||
<input
|
||||
class="vs__search"
|
||||
:required="!selected"
|
||||
v-bind="attributes"
|
||||
v-on="events"
|
||||
/>
|
||||
</template>
|
||||
</v-select>
|
||||
```
|
||||
@@ -0,0 +1,176 @@
|
||||
## Getting and Setting
|
||||
|
||||
### `v-model`
|
||||
|
||||
The most common use case for vue-select is to have the chosen value synced with a parent component. vue-select
|
||||
takes advantage of the `v-model` syntax to sync values with a parent. The `v-model` syntax works with
|
||||
primitives and objects.
|
||||
|
||||
```html
|
||||
<v-select v-model="selected" />
|
||||
```
|
||||
|
||||
Note that when using the `multiple` prop, the `v-model` value will always be an array.
|
||||
|
||||
### Props and Events
|
||||
|
||||
Sometimes `v-model` might not fit your use case. For example, when working with [Vuex](https://vuex.vuejs.org),
|
||||
you'll need to trigger a mutation rather than mutating a value directly. In that case, maybe you need
|
||||
to bind a pre-selected value, and trigger a mutation when it changes.
|
||||
|
||||
vue-select exposes the `value` prop and an `input` event to enable this. This combo of props and
|
||||
events is also how Vue wires up the `v-model` syntax internally.
|
||||
|
||||
#### Prop: `value`
|
||||
|
||||
The `value` prop lets vue-select know what value is currently selected. It will accept strings,
|
||||
numbers or objects. If you're using a `multiple` v-select, you'll want to pass an array.
|
||||
|
||||
```html
|
||||
<v-select :value="selected" />
|
||||
```
|
||||
|
||||
::: tip 🤓
|
||||
Anytime you bind the `value` prop directly, you're responsible for updating the bound variable
|
||||
in your code using the `@input` event.
|
||||
:::
|
||||
|
||||
#### Event: `input`
|
||||
|
||||
The `input` event is triggered anytime the value state changes, and is emitted with the `value`
|
||||
state as it's only parameter.
|
||||
|
||||
#### Vuex Support
|
||||
|
||||
The `value` prop and `emit` event are very useful when using a state management tool, like Vuex.
|
||||
You can bind the selected value with `:value="$store.myValue"`, and use the `input` event to
|
||||
trigger a mutation, or dispatch an action – or anything else you might need to do when the selection
|
||||
changes.
|
||||
|
||||
```html
|
||||
<v-select :value="$store.myValue" @input="setSelected" />
|
||||
```
|
||||
|
||||
```js
|
||||
methods: {
|
||||
setSelected(value) {
|
||||
// trigger a mutation, or dispatch an action
|
||||
}
|
||||
}
|
||||
```
|
||||
## Transforming Selections
|
||||
|
||||
When the `options` array contains objects, vue-select returns the whole object as dropdown value
|
||||
upon selection. This approach makes no assumptions about the data you need, and provides a lot of
|
||||
flexibility. However, there will be situations where maybe you just need to return a single key
|
||||
from an object.
|
||||
|
||||
### Returning a single key with `reduce`
|
||||
|
||||
If you need to return a single key, or transform the selection before it is synced, vue-select
|
||||
provides a `reduce` callback that allows you to transform a selected option before it is passed to
|
||||
the `@input` event. Consider this data structure:
|
||||
|
||||
```js
|
||||
let options = [{code: 'CA', country: 'Canada'}];
|
||||
```
|
||||
|
||||
If we want to display the `country`, but return the `code` to `v-model`, we can use the `reduce`
|
||||
prop to receive only the data that's required.
|
||||
|
||||
```html
|
||||
<v-select :options="options" :reduce="country => country.code" label="country" />
|
||||
```
|
||||
|
||||
### Deep Nested Values
|
||||
|
||||
The `reduce` property also works well when you have a deeply nested value:
|
||||
|
||||
```
|
||||
{
|
||||
country: 'canada',
|
||||
meta: {
|
||||
code: 'ca'
|
||||
provinces: [...],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<v-select :options="options" :reduce="country => country.meta.code" label="country" />
|
||||
```
|
||||
|
||||
<reducer-nested-value />
|
||||
|
||||
## Single/Multiple Selection
|
||||
|
||||
By default, vue-select supports choosing a single value. If you need multiple values, use the
|
||||
`multiple` boolean prop, much the same way you would on an HTML `<select>` element. When `multiple`
|
||||
is true, `v-model` and `value` must be an array.
|
||||
|
||||
|
||||
```html
|
||||
<v-select multiple v-model="selected" :options="['Canada','United States']" />
|
||||
```
|
||||
<v-select multiple :options="['Canada','United States']" />
|
||||
|
||||
## Tagging
|
||||
|
||||
To allow input that's not present within the options, set the `taggable` prop to true.
|
||||
|
||||
```html
|
||||
<v-select taggable multiple />
|
||||
```
|
||||
|
||||
<v-select taggable multiple />
|
||||
|
||||
If you want added tags to be pushed to the options array, set `push-tags` to true.
|
||||
|
||||
```html
|
||||
<v-select taggable multiple push-tags />
|
||||
```
|
||||
|
||||
<v-select taggable multiple push-tags />
|
||||
|
||||
### Using `taggable` & `reduce` together
|
||||
|
||||
When combining `taggable` with `reduce`, you must define the `createOption` prop. The
|
||||
`createOption` function is responsible for defining the structure of the objects that Vue Select
|
||||
will create for you when adding a tag. It should return a value that has the same properties as the
|
||||
rest of your `options`.
|
||||
|
||||
If you don't define `createOption`, Vue Select will construct a simple object following this structure:
|
||||
`{[this.label]: searchText}`. If you're using `reduce`, this is probably not what your options look
|
||||
like, which is why you'll need to set the function yourself.
|
||||
|
||||
**Example**
|
||||
|
||||
We have a taggable select for adding books to a collection. We're just concerned about getting the
|
||||
book title added, and our server side code will add the author details in a background process. The
|
||||
user has already selected a book.
|
||||
|
||||
```js
|
||||
const options = [
|
||||
{
|
||||
title: "HTML5",
|
||||
author: {
|
||||
firstName: "Remy",
|
||||
lastName: "Sharp"
|
||||
}
|
||||
}
|
||||
];
|
||||
```
|
||||
|
||||
```html
|
||||
<v-select
|
||||
taggable
|
||||
multiple
|
||||
label="title"
|
||||
:options="options"
|
||||
:create-option="book => ({ title: book, author: { firstName: '', lastName: '' } })"
|
||||
:reduce="book => `${book.author.firstName} ${book.author.lastName}`"
|
||||
/>
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
### Using the `input` Event with Vuex
|
||||
|
||||
`vue-select` emits the `input` event any time the internal `value` is changed.
|
||||
This is the same event that allow the for the `v-model` syntax. When using
|
||||
Vuex for state management, you can use the `input` event to dispatch an
|
||||
action, or trigger a mutation.
|
||||
|
||||
```html
|
||||
<v-select
|
||||
@input="myAction"
|
||||
:options="$store.state.options"
|
||||
:value="$store.state.selected"
|
||||
></v-select>
|
||||
```
|
||||
|
||||
<CodePen url="aJQJyp" height="350"/>
|
||||
Reference in New Issue
Block a user