The `Picker` action set provides a search-based interface to help users find and select one or more resources. Unlike the [ResourcePicker](/docs/api/app-bridge/previous-versions/actions/resourcepicker), it provides a lower-level API where you are in charge of providing the data as well as implementing search or pagination features. A close-up image of a picker. The picker displays the title: Picker and a search input field with the label: Search resources. Below the search interface are rows of placeholder resources. Resource 1 and variant 1 are both selected. The picker features two buttons: a white button with the label Cancel, and a green button with the label Select. You can use the contextual save bar in the following ways: 1. [Plain JavaScript](#plain-javascript) 2. [React component](#react) > Caution: > This feature is still under development. As such, the API might be updated without warning. ## Plain JavaScript Create an app and import the `unstable_Picker` module from `@shopify/app-bridge/actions`. This sample app is used throughout the examples below. > Note > In the following example, `config` is a valid App Bridge configuration object. Learn more about [configuring App Bridge](/docs/api/app-bridge/previous-versions/app-bridge-from-npm/app-setup#initialize-shopify-app-bridge-in-your-app). ```js import createApp from '@shopify/app-bridge'; import {unstable_Picker} from '@shopify/app-bridge/actions'; const app = createApp(config); ``` ### Create a picker to display a list of resources The following snippet creates a `Picker` with 2 resources. The first resource has 2 options. We're also specifying the title, search placeholder, and action labels. ```js const picker = unstable_Picker.create(app, { items: [ { id: 'resource1', name: 'Resource 1', options: [ { id: 'option1', name: 'Option1', }, { id: 'option2', name: 'Option2', }, ], }, { id: 'resource2', name: 'Resource 2', }, ], title: 'Select Resource', searchQueryPlaceholder: 'Search resources', primaryActionLabel: 'Save', secondaryActionLabel: 'Cancel', }); ``` ### Common Picker actions #### Selection and Cancellation The `Picker` has two main actions that you can subscribe to: `unstable_Picker.Action.SELECT` - This action is dispatched when the user triggers the primary action. This action generally corresponds to a selection event. It receives a `SelectPayload` argument, which is an `Object` with `id` and `selection` keys. The `selection` key is an array of all the selected items. `unstable_Picker.Action.CANCEL` - This action is dispatched when the user triggers the secondary action. This action generally corresponds to a cancelled event. ```js const picker = unstable_Picker.create(app, { items: [...], ... }); picker.subscribe(unstable_Picker.Action.SELECT, ({selection}) => { // Do something with `selection` }); picker.subscribe(unstable_Picker.Action.CANCEL, () => { // Picker was cancelled }); ``` #### Search The `Picker` has the `unstable_Picker.Action.SEARCH` search action that you can subscribe to. This action is dispatched when the user enters a search query string. It receives a `SearchPayload` argument, which is an `Object` with `id` and `searchQuery`. The `searchQuery` is a string. ```js const picker = unstable_Picker.create(app, { items: [...], ... }); picker.subscribe(unstable_Picker.Action.SEARCH, ({searchQuery}) => { // Do something with the searchQuery // You can then call picker.set({items: [...]}) in order to update the items with the result of the search query. }); ``` #### Pagination The `Picker` has the `unstable_Picker.Action.LOAD_MORE` pagination action that you can subscribe to. To enable this option make sure to set `canLoadMore` to `true` when creating your picker instance. This action is dispatched when the user reaches the bottom of the list of items. It does not have any arguments. ```js const picker = unstable_Picker.create(app, { items: [...], ... }); picker.subscribe(unstable_Picker.Action.LOAD_MORE, () => { // Do something to load additional data // You can then call picker.set({items: [...]}) in order to update the items the additional items loaded. }); ``` ### Options #### items - default value: `[]` - optional - type: `BaseResource[]` - note: `items` takes an array of minimal resource objects, which only need to contain a resource `id` and a `name` value. A resource may also contain child options. For example: ```js const picker = unstable_Picker.create(app, { items: [ { id: 'customResource1', name: 'Custom Resource 1', options: [ { id: 'option1', name: 'Option1', }, { id: 'option2', name: 'Option2', }, ], }, { id: 'customResource2', name: 'Custom Resource 2', }, ], ... }); ``` #### selectedItems - default value: `[]` - optional - type: `BaseResource[]` - note: `selectedItems` takes an array of minimal resource objects, which only need to contain a resource id (in GraphQL ID format, ie 'gid://shopify/Product/1'). Resources may also contain selected options. If no option is specified, all options are selected. #### maxSelectable - default value: `0` - optional - type: `number` - note: Limits the total number of selections to a maximum of the passed value, or `0` for no limit. #### title - default value: `undefined` - optional - type: `string` - note: Used as the title of the modal. #### loading - default value: `false` - optional - type: `boolean` - note: Indicates if the picker should be in a loading state. #### searchQueryPlaceholder - default value: `undefined` - optional - type: `string` - note: Used as the placeholder in the search input. #### searchQuery - default value: `undefined` - optional - type: `string` - note: The search query to be displayed in the search input field. #### primaryActionLabel - default value: `undefined` - optional - type: `string` - note: Label to be used on the primary action button. #### secondaryActionLabel - default value: `undefined` - optional - type: `string` - note: Label to be used on the secondary action button. #### canLoadMore - default value: `false` - optional - type: `boolean` - note: Whether the Picker can load more items on the list. #### loadingMore - default value: `false` - optional - type: `boolean` - note: Indicates if the Picker is currently loading more items. #### emptySearchLabel - default value: `undefined` - optional - type: `EmptySearchLabel` - note: `emptySearchLabel` takes an object that describes the interface of the picker when there is no item to display. For example: ```js const picker = unstable_Picker.create(app, { items: [], emptySearchLabel: { title: 'No resources', description: 'There are no resources to display', withIllustration: true, } }); ``` ### Subscribe to actions You can subscribe to `Picker` actions by calling subscribe. This returns a method that you can call to unsubscribe from the action. For example: ```js const picker = unstable_Picker.create(app, { ... }); const selectUnsubscribe = picker.subscribe(unstable_Picker.Action.SELECT, ({selection}) => { // Do something with `selection` }); const cancelUnsubscribe = picker.subscribe(unstable_Picker.Action.CANCEL, () => { // Picker was cancelled }); // Unsubscribe to actions selectUnsubscribe(); cancelUnsubscribe(); ``` ### Unsubscribe You can call unsubscribe to remove all subscriptions on the picker: ```js const picker = unstable_Picker.create(app, { ... }); picker.subscribe(unstable_Picker.Action.SELECT, () => { // Do something with `selection` }); picker.subscribe(unstable_Picker.Action.CANCEL, () => { // Picker was cancelled }); // Unsubscribe from all actions picker.unsubscribe(); ``` ### Dispatch actions ```js const picker = unstable_Picker.create(app, { ... }); // Open the picker picker.dispatch(unstable_Picker.Action.OPEN); ``` ### Update options You can call the `set` method with partial picker options. This automatically triggers the update action on the picker and merges the given options with the existing options: ```js const picker = unstable_Picker.create(app, { ... }); picker.set({items: [/* a list of items*/]}); ``` ## React ### Example code Import the `Provider` and `unstable_Picker` component from `@shopify/app-bridge-react`. > Note > In the following example, `config` is a valid App Bridge configuration object. Learn more about [configuring App Bridge](/docs/api/app-bridge/previous-versions/app-bridge-from-npm/app-setup#initialize-shopify-app-bridge-in-your-app). > Note > When using the App Bridge React library, you need to wrap all of your App Bridge React code inside of a single App Bridge [`Provider`](/docs/api/app-bridge/previous-versions/app-bridge-from-npm/using-react#provider). ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import { Provider, unstable_Picker as Picker } from '@shopify/app-bridge-react'; function MyApp() { return ( ); } const root = document.createElement('div'); document.body.appendChild(root); ReactDOM.createRoot(root).render(); ``` ### Props | Name | Type | Description | Required | | ---------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | open | `boolean` | Whether the picker is open or not. | Yes | | items | `BaseResource[]` | The list of items to display. | Yes | | canLoadMore | `boolean` | Whether the Picker can load more items on the list. | No | | selectedItems | `BaseResource[]` | The items which are selected. | No | | maxSelectable | `number` | Limits the total number of selections to a maximum of the passed value, or `0` for no limit. | No | | title | `string` | Used as the title of the modal. | No | | loading | `boolean` | Indicates if the Picker should be in a loading state. | No | | loadingMore | `boolean` | Indicates if the Picker is currently loading more items. | No | | searchQueryPlaceholder | `string` | Used as the placeholder in the search input. | No | | searchQuery | `string` | The search query to be displayed in the search input field. | No | | primaryActionLabel | `string` | Label to be used on the primary action button. | No | | secondaryActionLabel | `string` | Label to be used on the secondary action button. | No | | emptySearchLabel | `EmptySearchLabel` | An object that describes the interface of the picker when there is no item to display. | No | | onCancel | `() => void` | Callback when the user triggers the secondary action. | No | | onSelect | `(selectPayload: SelectPayload) => void` | Callback when a selection has been made. It receives a `SelectPayload` argument, which is an `Object` with `id` and `selection` keys. The `selection` key is an array of all the selected resources. | No | | onSearch | `(searchPayload: SearchPayload) => void` | Callback when the user enters a search query string. It receives a SearchPayload argument, which is an Object with id and `searchQuery`. The `searchQuery` is a string. | No | | onLoadMore | `() => void` | Callback when the user reaches the bottom of the list of items. It does not have any argument. | No |