Visual Picker in LWC – Dynamic and Reusable

A Reusable visual picker can be either radio buttons, checkboxes, or links that are visually enhanced. We have two types of Dyanmic Visual Picker, they are:- Coverable and Non-Coverable. Content comes in three sizes – small, medium (default) or large. The default uses radio buttons, allowing the user to pick only one. To allow multiple selections, follow the checkbox examples below.

Visual Picker in LWC - Dynamic and Reusable A Reusable visual picker can be either radio buttons, checkboxes, or links that are visually enhanced.

Business Use-CaseReusable Visual Picker

Business wants to have ability to select options visually. Architect suggested to have a reusable visual picker component based on slds design. The content inside the picker should be dynamic.

Implementation – Visual Picker

We are going to create two Lightning Web Components. They are:-

  1. reusableVisualPicker
  2. reusableVisualPickerElement

reusableVisualPickerElement

This component will have individual picker element. It will be called inside reusableVisualPicker component inside the iteration.

reusableVisualPickerElement.html

<template>
    <div class={pickerSize}>
        <input type={pickerType} id={pickerInputId} value={pickerInputValue} name={pickerInputName} onchange={handleSelect}/>
        <label for={pickerInputId}>
            <span class="slds-visual-picker__figure slds-visual-picker__text slds-align_absolute-center">
                <slot name="pickertext">{defaultPickerText}</slot>
            </span>
            <span class="slds-visual-picker__body">
                <slot name="pickerbody">{defaultPickerBody}</slot>
            </span>
            <span if:true={pickerChecked} class="slds-icon_container slds-visual-picker__text-check">
                <lightning-icon icon-name="utility:check" alternative-text="Connected" size="xx-small"
                    title="xx-small size"></lightning-icon>
            </span>
        </label>
    </div>
</template>

reusableVisualPickerElement.js

The definition of the public properties used in reusable picker element component are following:-

  • pickerInputId – This is used for providing the unique id to each picker
  • pickerInputName – This is provided for name attribute in input
  • pickerInputValue – this is used to hold the value of picker within the component
  • defaultPickerText – This is used for text inside the
  • defaultPickerBody – ‘Deafult picker body text’;
  • pickerChecked – this is used to control the checked style in picker
  • pickerType – define the multi select of single select in picker component
  • pickerSize -defines the size of the picker
import { LightningElement, api } from 'lwc';

export default class ReusableVisualPickerElement extends LightningElement {
    @api pickerInputId = 'visual-picker-94';
    @api pickerInputName = 'example-unique-name-36';
    @api pickerInputValue;
    @api defaultPickerText = 'Default picker text';
    @api defaultPickerBody = 'Deafult picker body';
    @api pickerChecked;
    @api pickerType = 'checkbox';
    @api pickerSize = 'slds-visual-picker slds-visual-picker_medium';
    
    handleSelect(event){
        this.pickerInputValue = event.target.checked;
        this.pickerChecked = event.target.checked;
        // Creates the event
        const selectedEvent = new CustomEvent('valueselected', {
            detail: { 
                value: event.target.checked, 
                id: this.pickerInputId 
            }
        });
        //dispatching the custom event
        this.dispatchEvent(selectedEvent);        
    }
}

reusableVisualPickerElement.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <isExposed>false</isExposed>
</LightningComponentBundle>

reusableVisualPicker

This component will be wrapper of reusableVisualPickerElement component. We will be demonstrating two examples:-

  1. Single Select Picker Example with Small Size
  2. Multi Select Example with Medium Size

Ideally when you have to use reusableVisualPickerElement, you have to use like below. Content inside slot named pickertext will go inside the picker box whereas slot named pickerbody will go below the box.

<fieldset class="slds-form-element">
    <legend class="slds-form-element__legend slds-form-element__label">
        Single Select Visual Picker Example with Small Size
    </legend>
    <div class="slds-form-element__control">
        <template for:each={plansListForSingleSelect} for:item="plan">
            <c-reusable-visual-picker-element key={plan.name} 
                picker-size="slds-visual-picker slds-visual-picker_small"
                picker-type="radio" picker-input-id={plan.id} onvalueselected={handleSelectSingle}>
                <span slot="pickertext"> 
                    <p class="slds-text-heading_large">{plan.amount}</p>
                    <p class="slds-text-title">{plan.amountinfo}</p>
                </span>
                <span slot="pickerbody">
                    <p class="slds-text-heading_small">{plan.name}</p>
                    <p class="slds-text-title">{plan.helptext}</p>
                </span>                    
            </c-reusable-visual-picker-element>
        </template>
    </div>
</fieldset>

reusableVisualPicker.html

<template>
    <lightning-card title="Visual Picker" icon-name="custom:custom63">
        <div class="slds-var-m-around_large">
            <fieldset class="slds-form-element">
                <legend class="slds-form-element__legend slds-form-element__label">
                    Single Select Visual Picker Example with Small Size
                </legend>
                <div class="slds-form-element__control">
                    <template for:each={plansListForSingleSelect} for:item="plan">
                        <c-reusable-visual-picker-element key={plan.name} 
                            picker-size="slds-visual-picker slds-visual-picker_small"
                            picker-type="radio" picker-input-id={plan.id} onvalueselected={handleSelectSingle}>
                            <span slot="pickertext"> 
                                <p class="slds-text-heading_large">{plan.amount}</p>
                                <p class="slds-text-title">{plan.amountinfo}</p>
                            </span>
                            <span slot="pickerbody">
                                <p class="slds-text-heading_small">{plan.name}</p>
                                <p class="slds-text-title">{plan.helptext}</p>
                            </span>                    
                        </c-reusable-visual-picker-element>
                    </template>
                </div>
            </fieldset>
            <template for:each={plansListForSingleSelect} for:item="plan">
                <p key={plan.id}>{plan.name} - Selected : {plan.selected}</p>
            </template>
            <fieldset class="slds-form-element">
                <legend class="slds-form-element__legend slds-form-element__label">
                    Multi Select Visual Picker Example with Medium Size
                </legend>
                <div class="slds-form-element__control">
                    <template for:each={plansListForMultiSelect} for:item="plan">
                        <c-reusable-visual-picker-element key={plan.name} 
                            picker-type="checkbox" picker-input-id={plan.id} onvalueselected={handleSelectMulti}>
                            <span slot="pickertext"> 
                                <p class="slds-text-heading_large">{plan.amount}</p>
                                <p class="slds-text-title">{plan.amountinfo}</p>
                            </span>
                            <span slot="pickerbody">
                                <p class="slds-text-heading_small">{plan.name}</p>
                                <p class="slds-text-title">{plan.helptext}</p>
                            </span>                    
                        </c-reusable-visual-picker-element>
                    </template>
                </div>
            </fieldset>
            <template for:each={plansListForMultiSelect} for:item="plan">
                <p key={plan.id}>{plan.name} - Selected : {plan.selected}</p>
            </template>
        </div>
    </lightning-card>
</template>

reusableVisualPicker.js

We have hardcoded the visual picker detail list. The JS file aslo handles the select event coming from resuableVisualPickerElement component.

import { LightningElement, track } from 'lwc';

export default class ReusableVisualPicker extends LightningElement {
    @track plansListForSingleSelect = [
        {
            id: 1,
            name : 'Lightning Professional', 
            amount: '$30', 
            helptext: 'Complete service CRM for teams of any size',
            amountinfo: 'USD/user/month *',
            selected: false
        },
        {
            id: 2,
            name : 'Lightning Enterprise', 
            amount: '$150', 
            helptext: 'Everything you need to take support to the next level',
            amountinfo: 'USD/user/month *',
            selected: false
        }
    ];

    @track plansListForMultiSelect = [
        {
            id: 1,
            name : 'Lightning Professional', 
            amount: '$30', 
            helptext: 'Complete service CRM for teams of any size',
            amountinfo: 'USD/user/month *',
            selected: false
        },
        {
            id: 2,
            name : 'Lightning Enterprise', 
            amount: '$150', 
            helptext: 'Everything you need to take support to the next level',
            amountinfo: 'USD/user/month *',
            selected: false
        }
    ];

    handleSelectMulti(event){
        this.plansListForMultiSelect.forEach(element => {
            if(element.id == event.detail.id){
                element.selected = event.detail.value;
            }
        });        
    }

    handleSelectSingle(event){
        this.plansListForSingleSelect.forEach(element => {
            if(element.id == event.detail.id){
                element.selected = event.detail.value;
            }else{
                element.selected = false;
            }
        });        
    }

}

reusableVisualPicker.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>  

Demo – Reusable Visual Picker

Leave a Reply