Visual Design Studio is designed to be user-friendly to non-technical users. However, the code block allows more technical users to leverage additional customization options to their guides. This article provides custom code snippets that let you customize your guides in various ways.
Warning: The examples in this article use custom code snippets to help you extend the capabilities of Pendo products. However, there is no warranty, SLA, or support available for their use. All snippets are free to use, but custom code is outside the remit of our Technical Support team's responsibilities. If you have a request for creating new snippets, modifying existing snippets, or customizing functionality, contact Pendo Professional Services (services@pendo.io) instead. These requests require a custom services contract with Pendo.
Note: The Visual Design Studio re-runs your code continuously as you write it. If you want to write ES6-compliant code, be aware that using const
prevents your code from re-running. This is because variables declared with const
are already defined on subsequent executions. Pendo recommends either wrapping your javascript in an IIFE
, or using let
or var
to avoid this.
Add a code block
- Create a new guide or edit an existing one.
- Add a building block and scroll down to Code Block in the Advanced section. See Add guide content using building blocks for more information about how to add a building block.
- Add the code to the relevant tab and select Done.
Add accordion dropdowns to guide content
You can add accordion dropdowns to your guide content.
Add a code block and then add the following three code snippets for HTML, CSS, and Javascript to the respective tab in the Edit Code window.
HTML tab
<div class="accordion">
<!-- Dropdown 5 -->
<!--
<div class="a-container">
<p class="a-btn">Accordion dropdown code<span></span></p>
<div class="a-panel">
</div>
</div>
-->
<!-- Dropdown 1 -->
<div class="a-container">
<p class="a-btn">Your text goes here.<span ></span></p>
<div class="a-panel">
<script src="Media file goes here" async></script><script src="https://fast.wistia.com/assets/external/E-v1.js" async></script><div class="wistia_responsive_padding" style="padding:56.25% 0 0 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><div class="wistia_embed wistia_async_zi5ms8ast1 videoFoam=true" style="height:100%;position:relative;width:100%"><div class="wistia_swatch" style="height:100%;left:0;opacity:0;overflow:hidden;position:absolute;top:0;transition:opacity 200ms;width:100%;"><img src="https://fast.wistia.com/embed/medias/zi5ms8ast1/swatch" style="filter:blur(5px);height:100%;object-fit:contain;width:100%;" alt="" aria-hidden="true" onload="this.parentNode.style.opacity=1;" /></div></div></div></div>
</div>
</div>
<!-- Dropdown 2 -->
<div class="a-container">
<p class="a-btn">Your text goes here.<span></span></p>
<div class="a-panel">
<script src="Media file goes here" async></script><script src="https://fast.wistia.com/assets/external/E-v1.js" async></script><div class="wistia_responsive_padding" style="padding:56.25% 0 0 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><div class="wistia_embed wistia_async_wzh5bzwg5x videoFoam=true" style="height:100%;position:relative;width:100%"><div class="wistia_swatch" style="height:100%;left:0;opacity:0;overflow:hidden;position:absolute;top:0;transition:opacity 200ms;width:100%;"><img src="https://fast.wistia.com/embed/medias/wzh5bzwg5x/swatch" style="filter:blur(5px);height:100%;object-fit:contain;width:100%;" alt="" aria-hidden="true" onload="this.parentNode.style.opacity=1;" /></div></div></div></div>
</div>
</div>
<!-- Dropdown 3 -->
<div class="a-container">
<p class="a-btn">Your text goes here.<span></span></p>
<div class="a-panel">
<script src="Media file goes here" async></script><script src="https://fast.wistia.com/assets/external/E-v1.js" async></script><div class="wistia_responsive_padding" style="padding:56.25% 0 0 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><div class="wistia_embed wistia_async_1btllcsz0d videoFoam=true" style="height:100%;position:relative;width:100%"><div class="wistia_swatch" style="height:100%;left:0;opacity:0;overflow:hidden;position:absolute;top:0;transition:opacity 200ms;width:100%;"><img src="https://fast.wistia.com/embed/medias/1btllcsz0d/swatch" style="filter:blur(5px);height:100%;object-fit:contain;width:100%;" alt="" aria-hidden="true" onload="this.parentNode.style.opacity=1;" /></div></div></div></div>
</div>
</div>
<!-- Dropdown 4 -->
<div class="a-container">
<p class="a-btn">Your text goes here.<span></span></p>
<div class="a-panel">
<script src="Media file goes here" async></script><script src="https://fast.wistia.com/assets/external/E-v1.js" async></script><div class="wistia_responsive_padding" style="padding:56.25% 0 0 0;position:relative;"><div class="wistia_responsive_wrapper" style="height:100%;left:0;position:absolute;top:0;width:100%;"><div class="wistia_embed wistia_async_nzwd88uvl9 videoFoam=true" style="height:100%;position:relative;width:100%"><div class="wistia_swatch" style="height:100%;left:0;opacity:0;overflow:hidden;position:absolute;top:0;transition:opacity 200ms;width:100%;"><img src="https://fast.wistia.com/embed/medias/nzwd88uvl9/swatch" style="filter:blur(5px);height:100%;object-fit:contain;width:100%;" alt="" aria-hidden="true" onload="this.parentNode.style.opacity=1;" /></div></div></div></div>
</div>
</div>
Note: This example uses a Wistia media file. You can use any media file within accordion dropdowns.
CSS tab
/* Panel style */
.accordion .a-container .a-panel {
width: 100%;
color: #262626;
-webkit-transition: all 0.2s ease-in-out;
transition: all 0.2s ease-in-out;
opacity: 0;
height: auto;
max-height: 0;
overflow: hidden;
padding: 0px 10px;
}
/* Panel style when active */
.accordion .a-container.active .a-panel {
padding: 10px 0;
opacity: 1;
height: auto;
max-height: 500px;
}
.a-btn {
cursor: pointer!important;
font-weight: 700;
}
.a-container {
padding: 14px 0 4px;
border-bottom: 1px #EFEEF2 solid;
}
.a-btn::after {
background-image: url("https://www.pendo.io/wp-content/themes/pendo-components/assets/images/pendo/components/chevron-down-icon@2x.png");
background-size: contain;
background-repeat: no-repeat;
display: inline;
position: absolute;
white-space: pre;
content: "\00a0";
width: 10px;
margin-top: 7px;
right: 40px;
}
#pendo-row-90251c5c, #pendo-text-7fe456a2 { display: none !important }
.pill-button {
background-color: #fff;
border: none;
color: #128397;
padding: 8px 12px;
text-align: center;
text-decoration: none;
display: inline-block;
margin: 2px 4px;
cursor: pointer;
border-radius: 16px;
border: 1px #128397 solid;
font-weight: 400;
}
.pill-checkbox:checked + label {
background-color: #128397;
color: #fff;
}
input[type="checkbox"] {
display: none;
}
Javascript tab
function initAcc(elem, option){
if (!pendo.isAccordionEventListenerAdded == true) {
//addEventListener on mouse click
document.addEventListener('click', function (e) {
//check is the right element clicked
if (!e.target.matches(elem+' .a-btn')) return;
else{
//check if element contains active class
if(!e.target.parentElement.classList.contains('active')){
if(option==true){
//if option true remove active class from all other accordions
var elementList = document.querySelectorAll(elem +' .a-container');
Array.prototype.forEach.call(elementList, function (e) {
e.classList.remove('active');
});
}
//add active class on cliked accordion
e.target.parentElement.classList.add('active');
}else{
//remove active class on cliked accordion
e.target.parentElement.classList.remove('active');
}
}
});
}
pendo.isAccordionEventListenerAdded = true;
}
//activate accordion function
initAcc('.accordion', true);
Add confetti to a guide
You can add confetti to a guide to add some flair when announcing a big update or a new offering, or anything you’re excited about.
- Add a code block and then add the code snippet below to the Javascript tab in the Edit Code window.
- To adjust the confetti colors, find the RGB codes for your branding and update this section of the code:
// https://github.com/mathusummut/confetti.js
const confetti = {
maxCount: 150, // set max confetti count
speed: 2, // set the particle animation speed
frameInterval: 15, // the confetti animation frame interval in milliseconds
alpha: 1.0, // the alpha opacity of the confetti (between 0 and 1, where 1 is opaque and 0 is invisible)
gradient: false, // whether to use gradients for the confetti particles
start: null, // call to start confetti animation (with optional timeout in milliseconds, and optional min and max random confetti count)
stop: null, // call to stop adding confetti
toggle: null, // call to start or stop the confetti animation depending on whether it's already running
pause: null, // call to freeze confetti animation
resume: null, // call to unfreeze confetti animation
togglePause: null, // call to toggle whether the confetti animation is paused
remove: null, // call to stop the confetti animation and remove all confetti immediately
isPaused: null, // call and returns true or false depending on whether the confetti animation is paused
isRunning: null // call and returns true or false depending on whether the animation is running
};
(function celebration() {
confetti.start = startConfetti;
confetti.stop = stopConfetti;
confetti.toggle = toggleConfetti;
confetti.pause = pauseConfetti;
confetti.resume = resumeConfetti;
confetti.togglePause = toggleConfettiPause;
confetti.isPaused = isConfettiPaused;
confetti.remove = removeConfetti;
confetti.isRunning = isConfettiRunning;
const supportsAnimationFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame;
const colors = ['rgba(217,252,255,', 'rgba(90,183,207,', 'rgba(18,130,151,'];
let streamingConfetti = false;
let animationTimer = null;
let pause = false;
let lastFrameTime = Date.now();
let particles = [];
let waveAngle = 0;
let context = null;
function resetParticle(particle, width, height) {
particle.color = `${colors[(Math.random() * colors.length) | 0]}${confetti.alpha})`;
particle.color2 = `${colors[(Math.random() * colors.length) | 0]}${confetti.alpha})`;
particle.x = Math.random() * width;
particle.y = Math.random() * height - height;
particle.diameter = Math.random() * 10 + 5;
particle.tilt = Math.random() * 10 - 10;
particle.tiltAngleIncrement = Math.random() * 0.07 + 0.05;
particle.tiltAngle = Math.random() * Math.PI;
return particle;
}
function toggleConfettiPause() {
if (pause) resumeConfetti();
else pauseConfetti();
}
function isConfettiPaused() {
return pause;
}
function pauseConfetti() {
pause = true;
}
function resumeConfetti() {
pause = false;
runAnimation();
}
function runAnimation() {
if (pause) return;
if (particles.length === 0) {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
animationTimer = null;
} else {
const now = Date.now();
const delta = now - lastFrameTime;
if (!supportsAnimationFrame || delta > confetti.frameInterval) {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
updateParticles();
drawParticles(context);
lastFrameTime = now - (delta % confetti.frameInterval);
}
animationTimer = requestAnimationFrame(runAnimation);
}
}
function startConfetti(timeout, min, max) {
const width = window.innerWidth;
const height = window.innerHeight;
window.requestAnimationFrame = (function() {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) {
return window.setTimeout(callback, confetti.frameInterval);
}
);
})();
let canvas = document.getElementById('confetti-canvas');
if (canvas === null) {
canvas = document.createElement('canvas');
canvas.setAttribute('id', 'confetti-canvas');
canvas.setAttribute('style', 'display:block;z-index:999999;pointer-events:none;position:fixed;top:0');
document.body.prepend(canvas);
canvas.width = width;
canvas.height = height;
window.addEventListener(
'resize',
function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
},
true
);
context = canvas.getContext('2d');
} else if (context === null) context = canvas.getContext('2d');
let count = confetti.maxCount;
if (min) {
if (max) {
if (min == max) count = particles.length + max;
else {
if (min > max) {
const temp = min;
min = max;
max = temp;
}
count = particles.length + ((Math.random() * (max - min) + min) | 0);
}
} else count = particles.length + min;
} else if (max) count = particles.length + max;
while (particles.length < count) particles.push(resetParticle({}, width, height));
streamingConfetti = true;
pause = false;
runAnimation();
if (timeout) {
window.setTimeout(stopConfetti, timeout);
}
}
function stopConfetti() {
streamingConfetti = false;
}
function removeConfetti() {
stop();
pause = false;
particles = [];
}
function toggleConfetti() {
if (streamingConfetti) stopConfetti();
else startConfetti();
}
function isConfettiRunning() {
return streamingConfetti;
}
function drawParticles(context) {
let particle;
let x;
let y;
let x2;
let y2;
for (let i = 0; i < particles.length; i++) {
particle = particles[i];
context.beginPath();
context.lineWidth = particle.diameter;
x2 = particle.x + particle.tilt;
x = x2 + particle.diameter / 2;
y2 = particle.y + particle.tilt + particle.diameter / 2;
if (confetti.gradient) {
const gradient = context.createLinearGradient(x, particle.y, x2, y2);
gradient.addColorStop('0', particle.color);
gradient.addColorStop('1.0', particle.color2);
context.strokeStyle = gradient;
} else context.strokeStyle = particle.color;
context.moveTo(x, particle.y);
context.lineTo(x2, y2);
context.stroke();
}
}
function updateParticles() {
const width = window.innerWidth;
const height = window.innerHeight;
let particle;
waveAngle += 0.01;
for (let i = 0; i < particles.length; i++) {
particle = particles[i];
if (!streamingConfetti && particle.y < -15) particle.y = height + 100;
else {
particle.tiltAngle += particle.tiltAngleIncrement;
particle.x += Math.sin(waveAngle) - 0.5;
particle.y += (Math.cos(waveAngle) + particle.diameter + confetti.speed) * 0.5;
particle.tilt = Math.sin(particle.tiltAngle) * 15;
}
if (particle.x > width + 20 || particle.x < -20 || particle.y > height) {
if (streamingConfetti && particles.length <= confetti.maxCount) resetParticle(particle, width, height);
else {
particles.splice(i, 1);
i--;
}
}
}
}
})();
(function () {
let confettiShown = false;
if (document.hidden) {
document.addEventListener('visibilitychange', () => {
if (!document.hidden && !confettiShown) {
confetti.start(3000);
confettiShown = true
}
});
} else {
confetti.start(3000);
confettiShown = true;
}
})();
Add a custom image URL to a button
To create a custom image button to link to a web address:
-
Add a code block and then add the following code to the HTML tab.
<div>
<a href="https://www.yourwebsitehere.com"><img src="https://content.pendo-internal.pendo.io/0QEQAhTvp96TaSrW-2qUpHK1Oyo/guide-media-16538ebc-822c-4396-ac06-27fa41017b2c"></a>.
</div> - Add your web address here <https://www.yourwebsitehere.com>
- Add the custom image URL here <https://content.pendo-internal.pendo.io/0QEQAhTvp96TaSrW-2qUpHK1Oyo/guide-media-16538ebc-822c-4396-ac06-27fa41017b2c>.
If you don't have an image URL:
- Add a new building block, select Image, and upload an image from your computer.
- Copy the image URL and paste it into the custom code block.
Styling the buttons
To adjust the size and style of the button hover state, add the following code to the CSS tab of the code block:
/*Link tiles styling END*/
.footer {
padding: 10px;
}
/*Styling for the Link Images*/
div{
width: 100%
}
.image-link{
margin-top: 4%;
margin-bottom: 0%;
margin-left: 0%;
margin-right: 10%;
width: 100%;
border: 1px #DADCE5;
border-style: solid;
font-weight: 600;
cursor: pointer;
border-radius: 6px;
}
.image-link:Hover {
box-shadow: 0px 2px 6px rgba(0, 0, 0, .2);
}
Launch the Resource Center from within a guide
You can launch the Resource Center directly inside a guide using a button action for quick access to all the resources. To do this, you need the button ID and guide ID to add to the code block.
- Create a new guide or edit an existing one.
- Add a building block and select Button.
- Select Launch Guide as the button action.
Note: There is no need to select a guide, you can leave this blank.
- Decide where you want to direct users and copy the guide ID:
-
Resource Center home view. Find the guide ID as shown in the image below.
- A specific module in the Resource Center. Find the guide ID as shown in the image below.
-
Resource Center home view. Find the guide ID as shown in the image below.
- To find the button ID to be used in launching the Resource Center, follow the instructions in the Tag buttons within guides article or use the Pendo Tagging Aid to find the ID.
- Add the code block and then add the following code snippet to the Javascript tab in the Edit Code window, inserting the guide ID and button ID.
pendo.dom('#pendo-button-{someLongID}').on('click', () =>
{pendo.onGuideDismissed();
pendo.showGuideById('guide-ID-here');
});
Add smiley face number scale polls in a guide
You can add custom code into a guide to transform all number scale polls within an active guide step into a set of “smiley faces”.
Note: This code is relevant for number scale polls only and does not affect any other poll type within Pendo Guides.
Requirements
A guide step must contain at least one number scale poll with exactly five number options, from 1-5.
Tip: You can work with Pendo Professional Services to create polls with more than or less than 5 faces.
Add the Custom Code
Add a code block and then add the code snippet below to the CSS tab in the Edit Code window.
/* Smiley Faces Source URLs */
@grey-face-1: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-76639afa-09bc-4226-a7b8-6c473d27b3fb');
@grey-face-2: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-c455ccff-6850-41db-9a02-7b44de37f4b2');
@grey-face-3: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-633f5928-a9f4-44ca-9d2b-5a2321b53100');
@grey-face-4: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-aa503f85-9e18-4020-b490-cdd88c3186c7');
@grey-face-5: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-5b91a381-c52a-451e-afc7-8b978af1cd54');
@color-face-1: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-e141cc7d-8d5d-483b-addf-fa995db76a74');
@color-face-2: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-bdeb7bde-392d-42c4-bee4-6b1b2e038d5e');
@color-face-3: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-73f3f214-f9a2-4045-a338-1d711a73d5c9');
@color-face-4: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-1402fa1c-ef86-4d22-8f81-cb2517c7b144');
@color-face-5: url('https://pendo-static-5926218839621632.storage.googleapis.com/RfG4pvMVSdCfUAR6XkWNvI7QKCo/guide-media-cc7ac2fb-3a60-4c58-9ef5-d29e5d0c58db');
/* Base Sizing & Color Styles */
label.pendo-radio[class*="_pendo-number-scale-poll-"] {
background-repeat: no-repeat;
background-size: contain;
color: rgba(0, 0, 0, 0.0)!important;
&:hover {
background-repeat: no-repeat!important;;
background-size: contain!important;;
color: rgba(0, 0, 0, 0.0)!important;
}
}
/* Default Faces State */
._pendo-number-scale-poll-1 { background-image: @grey-face-1; }
._pendo-number-scale-poll-2 { background-image: @grey-face-2; }
._pendo-number-scale-poll-3 { background-image: @grey-face-3; }
._pendo-number-scale-poll-4 { background-image: @grey-face-4; }
._pendo-number-scale-poll-5 { background-image: @grey-face-5; }
/* Hover Faces State */
label.pendo-radio._pendo-number-scale-poll-1:hover { background-image: @color-face-1!important; }
label.pendo-radio._pendo-number-scale-poll-2:hover { background-image: @color-face-2!important; }
label.pendo-radio._pendo-number-scale-poll-3:hover { background-image: @color-face-3!important; }
label.pendo-radio._pendo-number-scale-poll-4:hover { background-image: @color-face-4!important; }
label.pendo-radio._pendo-number-scale-poll-5:hover { background-image: @color-face-5!important; }
/* Active States for Faces */
input[type="radio"]._pendo-number-scale-poll-1-input:checked + label{
background-image: @color-face-1!important;
background-repeat: no-repeat!important;
background-size: contain!important;
background-color: #ffffff!important;
color: rgba(0, 0, 0, 0.0)!important;
}
input[type="radio"]._pendo-number-scale-poll-2-input:checked + label{
background-image: @color-face-2!important;
background-repeat: no-repeat!important;
background-size: contain!important;
background-color: #ffffff!important;
color: rgba(0, 0, 0, 0.0)!important;
}
input[type="radio"]._pendo-number-scale-poll-3-input:checked + label{
background-image: @color-face-3!important;
background-repeat: no-repeat!important;
background-size: contain!important;
background-color: #ffffff!important;
color: rgba(0, 0, 0, 0.0)!important;
}
input[type="radio"]._pendo-number-scale-poll-4-input:checked + label{
background-image: @color-face-4!important;
background-repeat: no-repeat!important;
background-size: contain!important;
background-color: #ffffff!important;
color: rgba(0, 0, 0, 0.0)!important;
}
input[type="radio"]._pendo-number-scale-poll-5-input:checked + label{
background-image: @color-face-5!important;
background-repeat: no-repeat!important;
background-size: contain!important;
background-color: #ffffff!important;
color: rgba(0, 0, 0, 0.0)!important;
}
Modify the Poll
Specific attributes of the poll, such as padding, margins, and background color behind the face images, can be modified with the standard Visual Design Studio functionality. For example, if you want to make the background white behind the transparent face images, you can modify that in the Styling tab of the Number Scale Poll building block.
Metrics
The metrics provided by these polls are the same as from a standard Number Scale Poll. In this case, 1 = Worst Reaction and 5 = Best Reaction.
Display guide when hovering over a target element
You can add code to allow for a guide to display when hovering over a target element.
To do this:
- Create a guide targeted to an element and select Target Element as the activation method.
-
Add a code block and then add the following code in the Javascript tab:
(function dismissGuideOnLeaveHover(dom) {
function mouseoverHandler(e) {
var tgt = e.target || e.srcElement;
if (!dom(tgt).closest(step.elementPathRule).length) {
pendo.onGuideDismissed();
pendo.detachEvent(window, 'mouseover', mouseoverHandler);
}
}
pendo.attachEvent(window, 'mouseover', mouseoverHandler);
})(pendo.dom)
Find building block classes
Each building block has an ID associated with it. You can use your browser inspect feature to find the class to use within your custom code. Right-click an element in a guide preview and select Inspect to open your browser's developer tool and find the CSS selector for the element that contains the unique ID.
Using this example inspection, it shows p#pendo-text-521f03a1
…: p
is the class #pendo-text-521f03a1
is the unique ID.