Profile
Back to NewsBack
GitHub Trending 7 min
Reader Mode
Fyerl/vue-awesome-picker: A Vue.js Picker Component

Fyerl/vue-awesome-picker: A Vue.js Picker Component

5 hours ago

vue-awesome-picker [![NPM Version][npm-image]][npm-url] [![NPM Downloads][downloads-image]][downloads-url]

A mobile picker component built with Vue.js and BetterScroll.

This is a Vue 2 component.
Recommended Vue version: [email protected] (or 2.7.x). Vue 3 is not supported.

Features

  • Supports single-column, multi-column, and cascade data
  • Built-in time and date picker modes
  • 3D wheel scrolling effect
  • Customizable title/text/colors

Demo

The demo enables Service Worker.

Installation

npm install vue-awesome-picker --save

Usage

// main.js
import AwesomePicker from 'vue-awesome-picker'

Vue.use(AwesomePicker)

<!-- See src/App.vue for a full example -->
<awesome-picker
  ref="picker"
  :data="picker.data"
  :anchor="picker.anchor"
  :textTitle="picker.textTitle"
  :textConfirm="picker.textConfirm"
  :textCancel="picker.textCancel"
  :colorTitle="picker.colorTitle"
  :colorConfirm="picker.colorConfirm"
  :colorCancel="picker.colorCancel"
  :swipeTime="picker.swipeTime"
  @cancel="handlePickerCancel"
  @confirm="handlePickerConfirm"
/>
methods: {
  show () {
    this.$refs.picker.show()
  }
}

Props

| Prop | Description | Options | Type | Default | | --- | --- | --- | --- | --- | | data | See the data section below | - | Array | [] | | anchor | See the anchor section below | - | Array | [] | | includeItem | Include the original selected option as item in each change or confirm result | - | Boolean | false | | type | Built-in picker type (no data required) | date, time | String | - | | textTitle | Title text | - | String | '' | | textConfirm | Confirm button text | - | String | Confirm | | textCancel | Cancel button text | - | String | Cancel | | colorTitle | Title color | - | String | #000000 | | colorConfirm | Confirm button color | - | String | #42b983 | | colorCancel | Cancel button color | - | String | #999999 | | swipeTime | Wheel swipe duration (better-scroll swipeTime) | - | Number | 1800 |

data

vue-awesome-picker determines whether the picker is normal or cascade by data shape, so please follow one of the formats below.

Normal picker (single or multi-column): pass a two-dimensional array. Each option can be a primitive value or an object with a value field. Object options display only value; use includeItem to retrieve fields such as id on confirmation.

[
  ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'],
  ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
]

Cascade picker: build hierarchy using children.

Each column follows the selected item in its parent column. Changing a parent resets all descendant columns to their first item. An empty or omitted children array ends the path, so confirm only contains the populated columns. Empty root data produces an empty selection ([]).

[
  {
    value: 'A',
    children: [
      { value: 'A-a' },
      { value: 'A-b' },
      { value: 'A-c' }
    ]
  },
  {
    value: 'B',
    children: [
      { value: 'B-a' },
      { value: 'B-b' }
    ]
  }
]

Changing the number of columns

Replace data to add or remove columns, including while the picker is open. For normal data, change the number of inner arrays. For cascade data, change the children hierarchy. Supply an anchor for the new data to select its initial path.

For example, switch from a single cascade column to two columns and reopen:

// Previously: this.picker.data = [{ value: 'A' }, { value: 'B' }]
this.picker.data = ['A', 'B'].map(value => ({
  value,
  children: ['X', 'Y', 'Z'].map(child => ({ value: value + child }))
}))
this.picker.anchor = [1, 2] // Selects B and BZ
this.$nextTick(() => this.$refs.picker.show())

Wait for Vue to pass updated props to the component before calling show().

anchor

anchor controls the default selected item for each wheel when the picker opens. It supports two formats. If no match is found, index 0 is selected.

Recommended object array format (same shape as the confirm event payload). When both index and value exist, index has higher priority.

Cascade anchors are resolved from parent to child. Each index must exist in the selected parent's children; an out-of-range index falls back to 0 at that level. When an anchor object only supplies value, that value is matched within the selected parent's children.

[
  { index: 0, value: 'A' },
  { index: 0, value: 'A-a' }
]

Index array format:

[0, 0]

Scrolling changes the temporary selection. Clicking Cancel or the outside mask discards those changes: reopening restores the selection from when that opening began, including the initial anchor or a selection confirmed on a previous opening. Cancellation does not emit confirm or modify the anchor prop. Replacing data or reactively updating anchor starts a new selection using the supplied anchor. An anchor update also applies while the picker is open and becomes the new cancellation baseline. It does not emit confirm.

Choosing the built-in date

Use anchor with type="date"; custom date data is not required. Date values include the Y, M, and D suffixes, with years from 1900 through 2100:

<awesome-picker ref="datePicker" type="date" :anchor="dateAnchor" />
data () {
  return { dateAnchor: [] }
},
methods: {
  showDate (year, month, day) {
    this.dateAnchor = [
      { value: ${year}Y },
      { value: ${month}M },
      { value: ${day}D }
    ]
    this.$nextTick(() => this.$refs.datePicker.show())
  }
}

For example, showDate(2024, 2, 29) opens at February 29, 2024, even after a previous confirmation or cancellation. The equivalent zero-based index anchor is [124, 1, 28]. Setting anchor to [] restores the built-in default date. Replace the anchor array as above, or use Vue 2 reactive mutations to edit it.

Methods

| Method | Description | | --- | --- | | show | Open the picker |

Events

| Event | Description | Payload | | --- | --- | --- | | change | A visible selection changes after scrolling and cascade synchronization finish | Same shape as confirm, including optional item | | confirm | Triggered after clicking the confirm button | [{ index, value }, ...]; with includeItem: [{ index, value, item }, ...] | | cancel | Triggered after clicking the cancel button or the mask outside the picker | - |

Previewing a selection before confirmation

Listen to change for a temporary selection and confirm for the final choice. change fires after the wheels finish moving, not for every item passed during a swipe. Cascade changes contain the complete synchronized path. Concurrently moving columns settle before a preview is emitted, and unchanged selections are not emitted again.

Opening, reopening, updating data or anchor, and restoring a cancelled selection do not emit change. A new opening or external data/anchor update establishes a new comparison baseline. change does not close the picker, commit the selection, or change its cancellation behavior.

<awesome-picker
  ref="picker"
  :data="options"
  @change="onChange"
  @confirm="onConfirm"
  @cancel="onCancel"
/>
data () {
  return { options: [['A', 'B', 'C']], preview: [], saved: [] }
},
methods: {
  onChange (selection) {
    this.preview = selection
  },
  onConfirm (selection) {
    this.saved = selection
    this.preview = selection
  },
  onCancel () {
    this.preview = this.saved
  }
}

Cancellation restores the picker's opening selection. It cannot undo effects already applied by your change handler, so discard or restore the application's preview in cancel, as above. Use confirm for actions that should be committed.

Returning ids and custom fields

Enable includeItem to read the original option alongside its selected index and display value. The default remains false, preserving the existing confirmation payload. change also includes item when enabled. This works with both normal columns and cascade objects.

<awesome-picker ref="peoplePicker" :data="people" include-item @confirm="onConfirm" />
data () {
  return {
    people: [[
      { value: 'Alice', id: 42, department: 'Design' },
      { value: 'Bob', id: 73, department: 'Engineering' }
    ]]
  }
},
methods: {
  onConfirm (selection) {
    const { index, value, item } = selection[0]
    console.log(index, value, item.id, item.department)
  }
}

item references the original option, including its custom fields and any children; treat it as read-only. For primitive options, item is that primitive. Items follow the selected indices and cascade path, so duplicate display values can still return distinct ids. The picker does not merge custom fields into index or value, and does not add item unless includeItem is enabled.

Development

git clone [email protected]:Fyerl/vue-awesome-picker.git
cd vue-awesome-picker
npm install
npm run dev
npm run build

Run the regression tests with Node.js 20 or later:

npm run test:date
npx playwright install chromium webkit
npm run test:browser

Browser tests rebuild the library and demo, then exercise the library bundle in Chromium and WebKit.

[npm-image]: https://img.shields.io/npm/v/vue-awesome-picker.svg?style=flat [npm-url]: https://npmjs.org/package/vue-awesome-picker [downloads-image]: https://img.shields.io/npm/dt/vue-awesome-picker.svg?style=flat [downloads-url]: https://npmjs.org/package/vue-awesome-picker

Chat with me