question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Add Dueling Picklist

See original GitHub issue

I’ve implemented a new <DuelingPicklist /> component for my team’s internal project (Salesforce employee), which I would like to contribute.

Proposed propTypes:

static propTypes = {
    /**
     * allows the user to reorder the second listbox of options
     */
    allowReordering: PropTypes.bool,

    /**
     * **Assistive text for accessibility**
     * This object is merged with the default props object on every render.
     * * `optionDragLabel`: Instructions on how to drag and drop with a keyboard.
     * * `moveSelectionUp`: Used by "up" reordering button.
     * * `moveSelectionDown`: Used by "down" reordering button.
     * * `moveSelectionToSecondCategory`: Used by "right" button, which moves selected items to selection.
     * * `moveSelectionToFirstCategory`: Used by "left" button, which removes selected items from selection.
     * * `tooltipIcon`: Used by tooltip, if a tooltip is being used.
     * * `itemLocked`: Used to label locked items.
     * * `itemsMovedToSelection`: Used in Aria Live area to inform user that items were moved to selection.
     * * `itemsRemovedFromSelection`: Used in Aria Live area to inform user that items were removed from selection..
     * * `itemsReorderedInSelection`: Used in Aria Live area to inform user that items were reordered in selection.
     */ 
    assistiveText: PropTypes.shape({
        optionDragLabel: PropTypes.string,
        moveSelectionUp: PropTypes.string,
        moveSelectionDown: PropTypes.string,
        moveSelectionToSecondCategory: PropTypes.string,
        moveSelectionToFirstCategory: PropTypes.string,
        tooltipIcon: PropTypes.string,
        itemLocked: PropTypes.string,
        itemsMovedToSelection: PropTypes.string,
        itemsRemovedFromSelection: PropTypes.string,
        itemsReorderedInSelection: PropTypes.string,
    }),

    /**
     * When true, the height of both listboxes will be the smallest height needed to show all items without having to scroll.
     */ 
    automaticHeightMinimization: PropTypes.bool,

    /**
     * When true, all interactions are disabled.
     */
    disabled: PropTypes.bool,
    
    /**
     * Event Callbacks
     * * `onChange`: Called when items are added or removed from `selection`
     */
    events: PropTypes.shape({
        onChange: PropTypes.func.isRequired,
    }).isRequired,

    /**
     * When true, shows a tooltip.
     */
    hasTooltip: PropTypes.bool,

    /**
     * Manually sets the height of both listboxes.
     */
    height: PropTypes.string,

    /**
     * Element ids (used for accessibility). If not provided, ids will be generated with shortid.
     * * `picklistGroupLabel`: id for labeling the `<DuelingPicklist />` component.
     * * `dragLiveRegion`: id for Aria Live element.
     * * `optionDragLabel`: id for describing how to use keyboard interactions.
     * * `firstCategoryLabel`: id for options listbox.
     * * `secondCategoryLabel`: id for selection listbox.
     */
    ids: PropTypes.shape({
        picklistGroupLabel: PropTypes.string,
        dragLiveRegion: PropTypes.string,
        optionDragLabel: PropTypes.string,
        firstCategoryLabel: PropTypes.string,
        secondCategoryLabel: PropTypes.string,
    }),

    /**
     * Labels
     * * `heading`: Heading for component.
     * * `firstCategory`: Label for options.
     * * `secondCategory`: Label for selection.
     * * `tooltip`: Label for tooltip.
     * * `selectedItems`: Labels selected items. Used in View Mode.
     */
    labels: PropTypes.shape({
        heading: PropTypes.string,
        firstCategory: PropTypes.string,
        secondCategory: PropTypes.string,
        tooltip: PropTypes.string,
        selectedItems: PropTypes.string,
    }),

    /**
     * Items in the first listbox
     * * `label`: Item label.
     * * `id`: Unique id for the item.
     * * `locked`: When true, a lock icon renders on the item, and the item cannot be moved to or from the selection.
     */
    options: PropTypes.arrayOf(PropTypes.shape({
        label: PropTypes.string.isRequired,
        id: PropTypes.string.isRequired,
        locked: PropTypes.bool,
    })).isRequired,

    /**
     * When true, the component will be render with responsive css classes applied. Any items longer than the space available will truncate with ellipses.
     */
    responsive: PropTypes.bool,

    /**
     * When true, a red asterisk will render, visually marking the item as required.
     */
    required: PropTypes.bool,

    /**
     * Items in the second listbox
     * * `label`: Item label.
     * * `id`: Unique id for the item.
     * * `locked`: When true, a lock icon renders on the item, and the item cannot be moved to or from the selection.
     */
    selection: PropTypes.arrayOf(PropTypes.shape({
        label: PropTypes.string.isRequired,
        id: PropTypes.string.isRequired,
        locked: PropTypes.bool,
    })).isRequired,

    /**
     * When true, the component will render in View Mode, which only shows the items in the selection.
     */
    viewMode: PropTypes.bool,
}

Issue Analytics

  • State:open
  • Created 5 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
kyleheddoncommented, Mar 6, 2019

@tanhengyeow I’m open you changes from you. I’ve been putting out some fires and will not likely be able to make changes to this for at least a couple weeks

1reaction
kyleheddoncommented, Dec 4, 2018

The ids are only used for accessibility (internally used by the component). My current impl does not actually take in ids as props, rather it creates them internally:

this.elementIds = {
	picklistGroupLabel: `picklist-group-label-${shortid.generate()}`,
	dragLiveRegion: `drag-live-region-${shortid.generate()}`,
	optionDragLabel: `option-drag-label-${shortid.generate()}`,
	firstCategoryLabel: `first-category-label-${shortid.generate()}`,
	secondCategoryLabel: `second-category-label-${shortid.generate()}`,
}

I saw other components take in id, so I thought I would allow the consumer to pass them in for the sake of consistency in the proposed props.

That being said, I can’t think of a good reason (from a best practices perspective) for allowing custom ids to be passed in. Taking in ids as props and doing it like ${this.getId()}-selected-listbox seems like a reasonable compromise.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dueling Picklist - Lightning Design System
A dueling-picklist is used to move options between two lists and is often referred to as a multi-select. Sometimes, the list options can...
Read more >
lightning-dual-listbox - documentation - Salesforce Developers
lightning-dual-listbox implements the Dueling Picklist blueprint in the Salesforce Lightning Design System (SLDS). Variants. Use the variant attribute with one ...
Read more >
Where are examples for using SLDS Dueling Listbox?
Drag to reorder in any list; Shift select several items in source or destination, then use the arrow buttons to move to either...
Read more >
Multiselect Picklist in Flow using Dual Listbox - SFDC Blogger
In this article I am going to use lightning-dual-listbox using LWC. A lightning-dual-listbox component represents two side-by-side listboxes.
Read more >
Dueling Picklists - Lightning Component - LinkedIn
Now user can select more than one contact from "Available Contact" and push it to "Selected Contact" picklist by clicking the right arrow...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found