We all love celebrating! And no celebration is complete without some Confetti in it. In Summer’19, Salesforce introduced Confetti celebration in Lightning Path.
https://releasenotes.docs.salesforce.com/en-us/summer19/release-notes/rn_sales_features_core_path.htm
But what if I tell you we can toss this confetti at a lot more places than just Lighnting Path? Sounds exciting, right?
But how do we do that?
Well, there is a JavaScript file which you can use in your Lightning Component as static resource and spread some love with that Confetti in your Salesforce org.
Link: https://cdn.jsdelivr.net/npm/canvas-confetti@0.2.1/dist/confetti.browser.min.js
I created a Lightning component to demo few of the confetti effects that we can do with this JavaScript file.
Code
showConfettiCMP.cmp
<aura:component implements="lightning:availableForFlowScreens,force:lightningQuickAction">
<aura:attribute name="colors" type="String[]" default="['#610B0B','#FFFF00','#FF00BF','#0040FF','#585858','#00FFBF','#FE642E','#FFBF00','#0101DF','#FF8000','#00FF00','#FF0040','#A901DB','#0B0B3B','#FF0000']"/>
<ltng:require scripts="{!$Resource.Confetti}"/>
<div class="slds-align_absolute-center">
<lightning:layout horizontalAlign="spread" verticalAlign="stretch" multipleRows="true" >
<lightning:layoutItem class="slds-align_absolute-center" size="6" smallDeviceSize="6" mediumDeviceSize="6" largeDeviceSize="6" flexibility="auto" padding="around-small">
<lightning:button variant="brand" class="buttonBox" label="Basic Cannon" onclick="{!c.basicCannon}"/>
</lightning:layoutItem>
<lightning:layoutItem class="slds-align_absolute-center" size="6" smallDeviceSize="6" mediumDeviceSize="6" largeDeviceSize="6" flexibility="auto" padding="around-small">
<lightning:button variant="brand" class="buttonBox" label="Fireworks" onclick="{!c.fireworks}"/>
</lightning:layoutItem>
<lightning:layoutItem class="slds-align_absolute-center" size="6" smallDeviceSize="6" mediumDeviceSize="6" largeDeviceSize="6" flexibility="auto" padding="around-small">
<lightning:button variant="brand" class="buttonBox" label="Confetti Shower" onclick="{!c.confettiShower}"/>
</lightning:layoutItem>
<lightning:layoutItem class="slds-align_absolute-center" size="6" smallDeviceSize="6" mediumDeviceSize="6" largeDeviceSize="6" flexibility="auto" padding="around-small">
<lightning:button variant="brand" class="buttonBox" label="Winner Celebration" onclick="{!c.winnerCelebration}"/>
</lightning:layoutItem>
<lightning:layoutItem class="slds-align_absolute-center" size="6" smallDeviceSize="6" mediumDeviceSize="6" largeDeviceSize="6" flexibility="auto" padding="around-small">
<lightning:button variant="brand" class="buttonBox" label="Burst Mode" onclick="{!c.busrtMode}"/>
</lightning:layoutItem>
<lightning:layoutItem class="slds-align_absolute-center" size="6" smallDeviceSize="6" mediumDeviceSize="6" largeDeviceSize="6" flexibility="auto" padding="around-small">
<lightning:button variant="brand" class="buttonBox" label="Canvas Confetti" onclick="{!c.canvasConfetti}"/>
</lightning:layoutItem>
</lightning:layout>
</div>
<br/>
<canvas id="customCanvas" aura:id="customCanvas" class="canvasCss">
</canvas>
</aura:component>
showConfettiCMPController.js
({
basicCannon : function(component, event, helper) {
confetti({
particleCount: 200,
startVelocity: 60,
spread: 150,
origin: {
y: 0.9
},
colors : component.get("v.colors")
});
},
fireworks : function(component, event, helper){
var end = Date.now() + (15 * 100);
var interval = setInterval(function() {
if (Date.now() > end) {
return clearInterval(interval);
}
confetti({
particleCount : 450,
startVelocity: 30,
spread: 360,
ticks: 60,
origin: {
x: Math.random(),
// since they fall down, start a bit higher than random
y: Math.random() - 0.2
},
colors : component.get("v.colors")
});
}, 200);
},
confettiShower : function(component, event, helper){
var end = Date.now() + (15 * 100);
(function frame() {
confetti({
particleCount: 10,
startVelocity: 0,
ticks: 300,
origin: {
x: Math.random(),
// since they fall down, start a bit higher than random
y: 0
},
colors: component.get("v.colors")
});
if (Date.now() < end) {
requestAnimationFrame(frame);
}
}());
},
winnerCelebration : function(component, event, helper) {
var end = Date.now() + (15 * 100);
(function frame() {
confetti({
particleCount: 10,
angle: 60,
spread: 25,
origin: {
x: 0,
y : 0.65
},
colors: component.get("v.colors")
});
confetti({
particleCount: 10,
angle: 120,
spread: 25,
origin: {
x: 1,
y : 0.65
},
colors: component.get("v.colors")
});
if (Date.now() < end) {
requestAnimationFrame(frame);
}
}());
},
canvasConfetti : function(component, event, helper){
debugger;
var canvas = document.getElementById("customCanvas"); //component.find("customCanvas");
// save this function... we'll save it to the canvas itself for
// the purpose of this demo
canvas.confetti = canvas.confetti || confetti.create(canvas, {
resize: true
});
canvas.confetti({
spread: 70,
origin: {
y: 1.2
},
colors : component.get("v.colors")
});
},
busrtMode : function(component, event, helper){
var end = Date.now() + (15 * 75);
// go Buckeyes!
var colors = ['#610B0B','#FFFF00','#FF00BF','#0040FF','#585858','#00FFBF','#FE642E','#FFBF00','#0101DF','#FF8000','#00FF00','#FF0040','#A901DB','#0B0B3B','#FF0000'];
(function frame() {
confetti({
particleCount: 7,
startVelocity: 25,
angle: 335,
spread: 10,
origin: {
x: 0,
y: 0,
},
colors: colors
});
confetti({
particleCount: 7,
startVelocity: 25,
angle: 205,
spread: 10,
origin: {
x: 1,
y: 0,
},
colors: colors
});
confetti({
particleCount: 7,
startVelocity: 35,
angle: 140,
spread: 30,
origin: {
x: 1,
y: 1,
},
colors: colors
});
confetti({
particleCount: 7,
startVelocity: 35,
angle: 40,
spread: 30,
origin: {
x: 0,
y: 1,
},
colors: colors
});
if (Date.now() < end) {
requestAnimationFrame(frame);
}
}());
}
})
showConfettiCMP.css
.THIS .buttonBox{
position:relative;
display: inline-block;
width: 100%;
max-width : 200px;
height: 100px;
padding: 1px !important;
border: 1px solid #d8dde6;
}
.THIS.canvasCss{
background-color: black;
width : 100%;
height : 250px;
}
Demo
For you guys, I created a small component and bundled it as an unmanaged package which you can use in directly in your flows for the Confetti effect. To extend the usability, you can add other interfaces in the component and use it accordingly.
Package: https://login.salesforce.com/packaging/installPackage.apexp?p0=04t6F000004DGGL&isdtp=p1
How would it look in flows?
Also, I have something interesting for you to play with. Consider giving this a try too!
https://www.kirilv.com/canvas-confetti/
Thank you for being an awesome reader! If you haven’t already, please subscribe to this blog for receiving all the latest updates straight into your inbox. 🙂
Thanks, Nads.
Brightened my Monday morning no end!
LikeLike
Pingback: Confetti & SweetAlert in Lightning Web Component - M Hamza Siddiqui
Pingback: Show Confetti using Lightning Aura Components – IntelliForce
I just installed package and got following error: Action failed: c:FlowConfettiCMP$controller$fireConfetti [confetti is not defined]
Can u help me? 🙂
LikeLike
Receiving an error on this can you assist revising component after new update ’23 ?
ltng:require$controller$init [$A.lockerService.isLockerNextenabledForComponent is not a function. (In ‘$A.lockerService.isLockerNextenabledForComponent(c)’;$A.lockerService.isLockerNextenabledForComponent is undefined)]
LikeLike
Aw man! These Salesforce releases are breaking everything. 🤦♂️
It seems to work in my dev org. Have you changed anything on the org?
LikeLike
No – I have not changed anything. I have just begun getting feedback our team was receiving this error.
LikeLike
This would require some debugging on your org as I cannot reproduce it.
LikeLike
How do I get the component to show in flow? I have installed the package and thats it.
LikeLike
You should be able to find the component in the flow screen element among the list of components in the left pane while configuring the screen element.
LikeLike
Is there any reason why the component wouldn’t show up in the left section of the screen flow?
LikeLike
It will be visible within the screen element (on left pane), not on the screen flow itself.
LikeLike
Sorry I found the issue, the package was installed in my production org and I didnt realize.
LikeLike
Haha, happens! 🙂
LikeLike
Is it possible to configure this as a flow ‘action’ rather than an element within a screen? I would like the confetti to trigger after an opportunity is closed won without the need to present another screen. Thanks
LikeLike
Hi,
It’s not possible with this version. However, it’s possible to have it the way you requested. However, it requires some additional effort and I only have very limited free time.
If it interests you, we can have a paid arrangement and I can build this for you. 🙂
LikeLike
Hello!
First of all, this is awesome!
I would like to try it out in DEV to show my business stakeholders, but it seems to install only in PROD. Any tips or workarounds?
Thanks!
LikeLike
Hey,
You can just change the login.salesforce.com to test.salesforce.com in the install link.
LikeLike