π§οΈ Creating a Rain and Thunder Effect in Salesforce with LWC
Have you ever wanted to make your Salesforce UI a little more interactive, fun, and visually engaging? While Lightning Web Components (LWCs) are typically used for business logic and data visualization, they can also be used to create immersive UI effects.
In this post, weβll walk through building a Rain and Thunder Lightning Web Component that creates a storm overlay with falling raindrops and random lightning flashes. This component can be placed on a record page, app page, or even a utility bar item to add a creative twist.
π― What Weβre Building
Our final component will:
βοΈ Show animated raindrops falling continuously.
βοΈ Generate random lightning flashes at intervals.
βοΈ Run as a transparent overlay, so it doesnβt block interaction with the page.
βοΈ Use only JavaScript, HTML, and CSS β no external libraries required.
π¨ Step 1: LWC Template
We start with a simple template that defines three layers:
- .storm-overlay β full-screen overlay that holds the rain and lightning effects.
- .rain β container for dynamically generated raindrops.
- .lightning β an element that flashes white to simulate lightning.
<template>
<div class=“storm-overlay”>
<div class=“rain” lwc:dom=“manual”></div>
<div class=“lightning”></div>
</div>
</template>
π Notice we used lwc:dom=”manual” for the .rain div. This allows us to directly inject raindrop elements via JavaScript.
π¨ Step 2: JavaScript Controller
The JavaScript handles two key responsibilities:
- Generate raindrops dynamically
- Trigger lightning flashes at random intervals
import { LightningElement } from ‘lwc’;
export default class RainAndThunderComponent extends LightningElement {
rendered = false;
lightningInterval;
renderedCallback() {
if (this.rendered) return;
this.rendered = true;
this.generateRain();
this.startLightning();
}
disconnectedCallback() {
clearInterval(this.lightningInterval);
}
generateRain() {
const rainElement = this.template.querySelector(‘.rain’);
if (!rainElement) return;
let drops = ”;
for (let i = 0; i < 200; i++) {
let left = Math.floor(Math.random() * 100);
let delay = Math.random().toFixed(2);
let duration = (0.3 + Math.random() * 0.7).toFixed(2);
let size = Math.random() * 2 + 2;
let height = Math.random() * 20 + 15;
drops += `<div class=”raindrop”
style=”left:${left}%;
width:${size}px;
height:${height}px;
animation-delay:${delay}s;
animation-duration:${duration}s;”></div>`;
}
rainElement.innerHTML = drops;
}
startLightning() {
const lightning = this.template.querySelector(‘.lightning’);
if (!lightning) return;
this.lightningInterval = setInterval(() => {
const flashes = Math.floor(Math.random() * 2) + 2;
let count = 0;
const flashInterval = setInterval(() => {
lightning.classList.add(‘flash’);
setTimeout(() => lightning.classList.remove(‘flash’), 150);
count++;
if (count >= flashes) {
clearInterval(flashInterval);
}
}, 300);
}, Math.floor(Math.random() * 4000) + 3000);
}
}
π A quick breakdown:
- generateRain() creates 200 <div> raindrops with random position, size, and animation timing.
- startLightning() randomly triggers a series of flashes (2β3 quick blinks) every 3β7 seconds.
π¨ Step 3: Styling with CSS
The magic of animation happens in CSS:
/* Transparent overlay */
.storm-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; /* donβt block clicks */
z-index: 9999;
overflow: hidden;
}
/* Raindrops */
.raindrop {
position: absolute;
top: -40px;
background: rgba(255, 255, 255, 0.8);
animation-name: fall;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
@keyframes fall {
0% Β { transform: translateY(0); opacity: 1; }
100% { transform: translateY(110vh); opacity: 0; }
}
/* Lightning flashes */
.lightning {
position: absolute;
width: 100%;
height: 100%;
background: white;
opacity: 0;
transition: opacity 0.15s;
}
.lightning.flash {
opacity: 0.9;
}
π Notes:
- Each .raindrop falls infinitely using the fall
- pointer-events: none; ensures the overlay doesnβt block clicks on the page.
- .lightning.flash makes the screen blink bright white briefly.
π¨ Step 4: Component Configuration (Meta File)
To make our component available in App Builder, we need to create the meta.xml configuration file. This file tells Salesforce where the LWC can be used (App Page, Record Page, or Home Page).
Hereβs the configuration:
<?xml version=“1.0”?>
<LightningComponentBundle xmlns=“http://soap.sforce.com/2006/04/metadata”>
<apiVersion>63.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightning__RecordPage</target>
</targets>
</LightningComponentBundle>
π Breakdown:
- <apiVersion>63.0</apiVersion> β Uses the latest API version (Spring β25 as of now).
- <isExposed>true</isExposed> β Makes the LWC visible in the App Builder.
- <targets> β Defines where this component can be placed (App, Home, or Record pages).
β‘ Demo Effect
When added to a record page in Salesforce App Builder:
- Youβll see raindrops falling across the screen.
- Every few seconds, the screen will flash with lightning, creating a stormy vibe.
It looks something like this:
π§οΈπ‘ Heavy rain with bright flashes of lightning illuminating your Salesforce record page.
π Enhancements
You can take this further:
- Add thunder sound effects with a small audio clip.
- Control rain intensity with a property (light drizzle vs heavy rain).
- Add rainbow effect after lightning for a magical touch.
β Conclusion
This component demonstrates how LWCs can be used beyond business logic β to create beautiful, immersive UI effects in Salesforce. With just a few lines of HTML, CSS, and JavaScript, we simulated a realistic rainstorm with thunder and lightning.
Next time you want to impress your team, add a little stormy flair to your Salesforce pages! π©οΈπ