UNPKG

react-dual-listbox

Version:
291 lines (228 loc) 14.2 kB
# react-dual-listbox [![npm](https://img.shields.io/npm/v/react-dual-listbox.svg?style=flat-square)](https://www.npmjs.com/package/react-dual-listbox) [![Build Status](https://img.shields.io/github/actions/workflow/status/jakezatecky/react-dual-listbox/main.yml?branch=master&style=flat-square)](https://github.com/jakezatecky/react-dual-listbox/actions/workflows/main.yml) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://raw.githubusercontent.com/jakezatecky/react-dual-listbox/master/LICENSE.txt) > A feature-rich dual listbox for React. ![Demo](demo.gif) ## Usage ### Installation Install the library using your favorite dependency manager: ``` shell yarn add react-dual-listbox ``` Using npm: ``` shell npm install react-dual-listbox --save ``` > **Note** &ndash; This library makes use of [Font Awesome][font-awesome] styles and expects them to be loaded in the browser. ### Include CSS The library's styles are available through one of the following files: * `node_modules/react-dual-listbox/lib/react-dual-listbox.css` * `node_modules/react-dual-listbox/src/scss/react-dual-listbox.scss` Either include one of these files in your stylesheets or utilize a CSS loader: ``` jsx import 'react-dual-listbox/lib/react-dual-listbox.css'; ``` ### Render Component The `DualListBox` is a [controlled][react-controlled] component. You must update the `selected` property in conjunction with the `onChange` handler if you want the selected values to change. Here is a minimal rendering of the component: ``` jsx import React, { useState } from 'react'; import DualListBox from 'react-dual-listbox'; import 'react-dual-listbox/lib/react-dual-listbox.css'; const options = [ { value: 'one', label: 'Option One' }, { value: 'two', label: 'Option Two' }, ]; function Widget() { const [selected, setSelected] = useState([]); return ( <DualListBox options={options} selected={selected} onChange={(newValue) => setSelected(newValue)} /> ); } ``` ### Optgroups This component also supports traditional `<optgroup>` elements through the use of the `options` key: ``` jsx const options = [ { label: 'Earth', options: [ { value: 'luna', label: 'Moon' }, ], }, { label: 'Mars', options: [ { value: 'phobos', label: 'Phobos' }, { value: 'deimos', label: 'Deimos' }, ], }, { label: 'Jupiter', options: [ { value: 'io', label: 'Io' }, { value: 'europa', label: 'Europa' }, { value: 'ganymede', label: 'Ganymede' }, { value: 'callisto', label: 'Callisto' }, ], }, ]; return <DualListBox options={options} />; ``` ### Disabling the Component or Options Pass in the `disabled` property to disable the entire component. Alternatively, individual options may be disabled on a per-item basis: ``` jsx const options = [ { label: 'Mars', disabled: true, options: [ { value: 'phobos', label: 'Phobos' }, { value: 'deimos', label: 'Deimos' }, ], }, { label: 'Jupiter', options: [ { value: 'io', label: 'Io' }, { value: 'europa', label: 'Europa', disabled: true }, { value: 'ganymede', label: 'Ganymede' }, { value: 'callisto', label: 'Callisto' }, ], }, ]; return <DualListBox options={options} />; ``` ### Filtering You can enable filtering of available and selected options by merely passing in the `canFilter` property: ``` jsx <DualListBox canFilter options={options} /> ``` Optionally, you can also override the default filtering function: ``` jsx <DualListBox canFilter filterCallback={(option, filterInput, { getOptionLabel }) => { if (filterInput === '') { return true; } return (new RegExp(filterInput, 'i')).test(getOptionLabel(option)); }} options={options} /> ``` In addition, you may control the filter text state, rather than leaving it up to the component: ``` jsx <DualListBox canFilter filter={{ available: 'europa', selected: '', }} options={options} onFilterChange={(filter) => { console.log(filter); }} /> ``` ### Action/Button Alignment By default, the component arranges the action buttons to the center. Another option is to align these actions to be above their respective lists: ``` jsx <DualListBox alignActions="top" options={options} /> ``` ### Preserve Select Ordering By default, `react-dual-listbox` will order any selected items according to the order of the `options` property. There may be times in which you wish to preserve the selection order instead. In this case, you can add the `preserveSelectOrder` property. > **Note** &ndash; Enabling this option hides `<optgroup>` associations in the selected listbox. ``` jsx <DualListBox options={options} preserveSelectOrder /> ``` To allow users to re-arrange their selections after moving items to the right, you may also pass in the `showOrderButtons` property. ### Restrict Available Options Sometimes, it may be desirable to restrict what options are available for selection. For example, you may have a control above the dual listbox that allows a user to search for a planet in the solar system. After selecting a planet, you restrict the available options to the moons of that planet. Use the `available` property in that case. ``` jsx // Let's restrict ourselves to the Jovian moons const available = ['io', 'europa', 'ganymede', 'callisto']; return <DualListBox options={options} available={available} />; ``` ### Changing the Default Icons By default, **react-dual-listbox** uses [Font Awesome][font-awesome] for the various icons that appear in the component. To change the defaults, simply pass in the `icons` property to override the defaults: ``` jsx <DualListBox ... icons={{ moveLeft: <span className="fa fa-chevron-left" />, moveAllLeft: [ <span key={0} className="fa fa-chevron-left" />, <span key={1} className="fa fa-chevron-left" />, ], moveRight: <span className="fa fa-chevron-right" />, moveAllRight: [ <span key={0} className="fa fa-chevron-right" />, <span key={1} className="fa fa-chevron-right" />, ], moveDown: <span className="fa fa-chevron-down" />, moveUp: <span className="fa fa-chevron-up" />, moveTop: <span className="fa fa-double-angle-up" />, moveBottom: <span className="fa fa-double-angle-down" />, }} /> ``` Alternatively, set the `iconsClass` property and define the icons in CSS. ### Additional `onChange` Details At times, it may be useful to know which options the user highlighted before triggering a change or which control group was responsible for the change. In these cases, you can pass additional parameters to the `onChange` function: ``` jsx const onChange = (selected, selection, controlKey) => { console.log('The user highlighted these options', selection); console.log('The following control triggered these changes', controlKey); }; ``` ### All Properties | Property | Type | Description | Default | | --------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------- | ---------------- | | `options` | array | **Required**. Specifies the list of options that may exist on either side of the dual list box. | | | `onChange` | function | **Required**. The handler called when the selected options change: `function(selected, selection, controlKey) {}`. | | | `alignActions` | string | A value specifying whether to align the action buttons to the `'top'` or `'middle'`. | `middle` | | `allowDuplicates` | bool | If true, duplicate options will be allowed in the selected list box. | `false` | | `available` | array | A subset of the `options` array to optionally filter the available list box. | `undefined` | | `availableRef` | function | A React function [ref][react-ref] to the "available" list box. | `null` | | `canFilter` | bool | If true, search boxes will appear above both list boxes, allowing the user to filter the results. | `false` | | `className` | string | An optional `className` to apply to the root node. | `null` | | `disabled` | bool | If true, both "available" and "selected" list boxes will be disabled. | `false` | | `filter` | object | A key-value map of `{ available: [value], selected: [value] }` to control the filter values (defaults to uncontrolled). | `null` | | `filterCallback` | function | The filter function to run on a given option and input string: `function(option, filterInput) {}`. See **Filtering**. | `() => { ... }` | | `getOptionLabel` | function | The function to resolve the **label** from an option. Defaults to `option => option.label`. | `() => { ... }` | | `getOptionValue` | function | The function to resolve the **value** from an option. Defaults to `option => option.value`. | `() => { ... }` | | `htmlDir` | string | The [directionality][mdn-directionality] of the component's elements. Set to `'rtl'` if using a right-to-left language. | `'ltr'` | | `icons` | object | A key-value pairing of action icons and their React nodes. See **Changing the Default Icons** for further info. | `{ ... }` | | `iconsClass` | string | A value specifying which overarching icon class to use. Built-in support for `fa5`, `fa6`, and `native` icons. | `'fa6'` | | `id` | string | An HTML ID prefix for the various sub elements. | `null` | | `lang` | object | A key-value pairing of localized text. See [`src/js/lang/default.js`][lang-file] for a list of keys. | `{ ... }` | | `moveKeys` | array | A list of [keyboard keys][mdn-key] that will trigger a toggle of the highlighted options. | `[' ', 'Enter']` | | `name` | string | A value for the `name` attribute on the hidden `<input />` element. This is potentially useful for form submissions. | `null` | | `onFilterChange` | function | A handler called when a filter input changes. Paired with `filter` when wanting to control the filter values. | `null` | | `preserveSelectOrder` | bool | If true, the order in which the available options are selected are preserved when the items are moved to the right. | `false` | | `required` | bool | If true, this component will require `selected` to be non-empty to pass a form validation | `false` | | `selected` | array | A list of the selected options appearing in the rightmost list box. | `[]` | | `selectedRef` | function | A React function [ref][react-ref] to the "selected" list box. | `null` | | `showHeaderLabels` | bool | If true, labels above both the available and selected list boxes will appear. These labels derive from `lang`. | `false` | | `showNoOptionsText` | bool | If true, text will appear in place of the available/selected list boxes when no options are present. | `false` | | `showOrderButtons` | bool | If true, a set of up/down buttons will appear near the selected list box to allow the user to re-arrange the items. | `false` | | `simpleValue` | bool | If true, the `selected` value passed in `onChange` is an array of string values. Otherwise, it is an array of options. | `true` | #### Option Properties | Property | Type | Description | | ---------- | ------ | ---------------------------------------------------------------------------------------------------------- | | `label` | string | **Required**. The text label for the given option. Use `getOptionLabel` to set a different key. | | `value` | mixed | **Required**. The text or numeric value for the given option. Use `getOptionValue` to set a different key. | | `disabled` | bool | If true, disables the option from selection. | | `title` | string | Adds the HTML `title` attribute to the option. | [react-controlled]: https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components [react-ref]: https://react.dev/learn/manipulating-the-dom-with-refs [font-awesome]: https://fontawesome.com [lang-file]: https://github.com/jakezatecky/react-dual-listbox/blob/master/src/js/lang/default.js [mdn-directionality]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir [mdn-key]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key