Creating a Rain and Thunder Effect in Salesforce with LWC

🌧️ 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:

  1. Generate raindrops dynamically
  2. 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! 🌩️🌈

Leave a Comment

Your email address will not be published. Required fields are marked *