Skip to main content

Multiselect Options Implementation in PX Engagement with Custom Attribute Updates

  • February 17, 2026
  • 1 reply
  • 1 view

  • Gainsight Employee ⭐️

In this post, we'll guide you through the implementation of a multiselect feature in PX engagement, where users can select different options visually through checkboxes with images. Our implementation captures user selections, updates a custom attribute upon submission, and closes the engagement.

 



Below, you'll find the HTML code that forms the core of this functionality, along with an explanation of what each part does.

 


<div id="imageForm" style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; margin-top: 20px;">
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Executive" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Executive" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80">
<div style="font-size: 14px; text-align: center;">Executive</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Clinical" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Clinical" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80">
<div style="font-size: 14px; text-align: center;">Clinical</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="IT" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="IT" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80">
<div style="font-size: 14px; text-align: center;">IT</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Data" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Data" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80">
<div style="font-size: 14px; text-align: center;">Data</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Auditor" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Auditor" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80">
<div style="font-size: 14px; text-align: center;">Auditor</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Communication" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Communication" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80">
<div style="font-size: 14px; text-align: center;">Communication</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Project Manager" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Project Manager" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80" id="px-7198f296-08f7-4e7a-88e2-3f4cf47b0132">
<div style="font-size: 14px; text-align: center;">Project Manager</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Trainer" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Trainer" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80" id="px-36541e43-fb79-42e9-ad19-3d4c69a2232f">
<div style="font-size: 14px; text-align: center;">Trainer</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="nVoq Admin" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s;">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="nVoq Admin" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80">
<div style="font-size: 14px; text-align: center;">nVoq Admin
</div>
</div>
<div class="image-checkbox" onclick="this.classList.toggle('selected'); this.style.borderColor = this.classList.contains('selected') ? '#007bff' : 'transparent'; this.style.boxShadow = this.classList.contains('selected') ? '0 0 10px rgba(0, 123, 255, 0.7)' : 'none';" data-value="Stakeholder" style="cursor: pointer; display: flex; flex-direction: column; align-items: center; margin: 0px 5px 10px; border: 2px solid transparent; transition: border-color 0.3s, box-shadow 0.3s; box-shadow: none;">
<img src="hhttps://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ98hHCI_jrnI-CHJy-UaWLKAY8YDSzNs-G3Q&s" alt="Stakeholder" style="width: 80px; height: 80px; display: block; margin-bottom: 5px;" width="80" height="80" id="px-10ec3897-10e4-4362-a48d-dceb92810712">
<div style="font-size: 14px; text-align: center;">Stakeholder</div>
</div>
</div>
<div style="display: flex; justify-content: center; margin-top: 20px;">
<button id="pxCustomButton-a4923ef5-39b6-4a70-8fc0-82d2c39836bf" type="button" style="margin-top: 20px; padding: 10px 20px; background-color: #007bff; color: #fff; border: none; cursor: pointer;" onclick="(function() {const selectedRolesStr =Array.from(document.querySelectorAll('.image-checkbox.selected')).map(box =&gt;box.getAttribute('data-value')).join(', ');console.log('Selected Roles:',selectedRolesStr);aptrinsic('set','user',{'Test_role':selectedRolesStr});})()" class="px-editor-selected-button-in-focus">Submit234567&nbsp;</button>
</div>

Explanation: Image Click Functionality and Backend Processing

  1. Image Selection Interaction:

    • When you click on any of the images (which function as checkboxes), the JavaScript onclick event is triggered.
    • Toggle Selection: The this.classList.toggle('selected') part of the JavaScript code toggles the selected class on or off for the clicked element. This acts as a visual indicator for selection.
  2. Backend Processing on Submission:

    • Upon clicking the Submit button, an immediately invoked function executes:
      • Collect Selection: The code Array.from(document.querySelectorAll('.image-checkbox.selected')).map(box => box.getAttribute('data-value')).join(', '); collects all elements with the selected class. It maps and retrieves the data-value for each selected item, converting this list into a comma-separated string (e.g., "Executive, IT").
      • Logging and Updates: It logs the selected roles to the console with console.log('Selected Roles:', selectedRolesStr); and updates a custom attribute using the aptrinsic function (aptrinsic('set', 'user', {'Test_role': selectedRolesStr});), sending the collected data to the backend for storage or analysis.
  3. Custom Attribute Update:

    • The custom attribute update allows the backend system to store the selected roles in the user’s profile or session record.

Steps to Implement Multiselect Options in PX Engagement

  1. Create a Custom Attribute in PX:

    • Before starting with the engagement, create a custom attribute in your PX instance to store the values received from the engagement. This will allow you to capture and manage user selections efficiently.
  2. Create a Single-Page Guide Engagement:

    • Begin by creating a new single-page guide engagement in your PX administration panel.
  3. Clear the HTML Code:

    • Remove any existing HTML code in the engagement editor to start with a blank canvas.
  4. Copy and Paste the Provided Code:

    • Copy the multiselect options code shared in this post and paste it into the HTML editor of your engagement. 
  5. Save the Engagement:

    • Save the engagement with the newly added code to ensure your changes are not lost.
  6. Add Closing Functionality:

    • Note Important: To enable the Submit button to close the engagement while updating the custom attribute, you will need to create an additional button temporarily.
    • Insert a new button into the engagement and configure it to perform the action of closing the engagement.
  7. Switch to Code View:

    • Change to the code view of the editor after configuring the temporary button to capture the button ID.
  8. Copy the Button ID:

    • Take note of the button ID for the button you created, as you will use it in your main submit button's code.
  9. Save the Engagement Again:

    • Save the engagement once more to store the newly captured button ID.
  10. Remove the Temporary Button:

    • Delete the temporary button you created earlier, as it is no longer needed.
  11. Update the Submit Button ID:

    • In the previously pasted code, locate the Submit button section and replace its onclick functionality to include the ID of the temporary button you just removed. Ensure it handles the closing of the engagement effectively.
  12. Swap Attribute Name:

    • In the function that updates the custom attribute, swap the attribute name in the following line of code:

      aptrinsic('set', 'user', {'Test_role': selectedRolesStr});

      Replace 'Test_role' with the name of the custom attribute you created in Step 1.
  13. Final Save:

    • Save the engagement once more to confirm all changes.

1 reply

link_black
Forum|alt.badge.img+2
  • Gainsight Employee ⭐️⭐️
  • February 17, 2026

This is a good example of using custom JavaScript/CSS within an Engagement.  Nice job ​@prraj.

 

A few additional points that could be valuable…

  • to use this custom JavaScript within the Engagement, the PX Subscription must have JavaScript Enabled for the Engagements.
  • The new PX User attribute data does not immediately show in the PX User Profile screen.  It will take a few minutes or longer to be visible there.
  • Using a different custom images and replacing those references in the sample HTML code’s “<img src=...” is recommended. 
  • Changing the role string values in each DIV’s “...data-value=...” will be required to customize this to match whatever role text needs to be collected for each selected image option before submitting.
  • In the HTML source code originally provided above, there is a small typo on the last “<img src=...” and “hhttp:/..” needs to be corrected to be “http://…” for an image to show.

 

Bonus Suggestion…

 

If you want to update PX Account Custom Attributes, the code that calls “… onclick=aptrinsic('set','user',{'Test_role':selectedRolesStr})... can be swapped out with a PX Identify call JavaScript call like this “...aptrinsic('identify',{'id':'{{User.id}}'},{'id':'{{Account.id}}','Test_role':selectedRolesStr})...

I discussed doing this in the following previous post, but it could be super useful to consider this use case for some “Account level” use cases too.

 

 

Happy PX-ing!