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 custom code snippets included in this article are intended to extend the capabilities of Pendo products. All snippets are free to use, and as such, there is NO WARRANTY, SLA or SUPPORT for these snippets. Please do not reach out to Pendo Support for help with these snippets, as custom code is outside of the remit of their team and responsibilities. Any requests to create new snippets, or modify/customize functionality within existing snippets should be forwarded to Pendo Professional Services (services@pendo.io) for scoping. These will require a custom services contract to complete the request.
Find building block classes
Each building block has an ID associated with it. Currently, you can use your browser inspect feature to find the class to use within your custom code. When Chrome users, for example, right-click and inspect an element in a Guide preview, they will see something like the following:

Using this example inspection, it shows p#pendo-text-521f03a1
…: p
is the class #pendo-text-521f03a1
is the unique ID
Unsure about CSS selectors? Take a look at this W3 article for reference.
Access the 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.
Access the code block and 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.
- Access the code block and 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:
-
Access the code block and 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.
- Access the code block and 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
Access the code block and 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.
Use Calendly to increase appointment rates
If your role requires you to engage with your customers more, you can use Calendly, together with Pendo, to help joint customers use the power of in-app messaging to increase the likelihood of a customer booking an appointment.
The benefits of this are:
- Increase appointment booking rates
- Use behavioral data to better target appointment messaging
Note: This feature is for the guides in your web app only. It is not relevant for guides in your mobile app.
Requirements
- Pendo account with Guidance
- Active Calendly account
Add a scheduled appointment to a guide
- Log into your Calendly account and create a new Event Type or find an existing event.
- Select Share on the event you want to embed in your guide.
- Navigate to Add to Website, select Embed inline, and then select Continue.
- Adjust the booking page settings and select Copy Code.
- Log in to Pendo and create a guide. You might want to create a multi-step guide with step one explaining the purpose of scheduling a conversation, and the second step presenting the Calendly calendar.
-
Add a Code Block by pasting the snippet you copied from Calendly into the HTML tab, then save the guide and publish it.
- Preview your guide to try it out.
Calendly guide embed example
Step one of the guide
Step two of the guide
That’s it! Create as many Calendly-powered guides as you need to effectively increase your appointment bookings.