Adding a Dynamic Sales Announcement Banner in Storefront: A Developer’s Guide to Using ScriptTag Bindings in Fynd Themes
In this document, we will learn how to add a discount banner to the Storefront to alert our customers of ongoing sale. We will achieve this using Storefront ScriptTag Bindings which injects script tags into the theme to provide custom functionalities.
Prerequisites
- Ensure that you have created an extension. Refer to Get Started for more details.
- Ensure that you have created a theme. Refer to Create a Theme for more details.
This tutorial is divided into two sections:
- Create a ScriptTag Binding
Insert custom JavaScript code withinscript
tag in an extension in Fynd Partners portal. - Apply Bindings to Theme
Create a ScriptTag Binding
Do the following steps to create a ScriptTag bindings:
- Login to Fynd Partners.
- In the left pane, click Extensions and select the extension you've created.
- Go to the Extension Setup and ensure that the Extension URL and permissions are correctly configured.
- In the Bindings section, click Manage.
- In the upper-right corner of the window, click Add to create new Bindings.
- Select Storefront in Interface Area dropdown list.
- Select ScriptTag from the Binding Type dropdown list.
- Enter a name for the Bindings.
- Copy and paste the following code in the Wrapper Code input:
<script>
document.addEventListener('DOMContentLoaded', function () {
const announcementData = {
title: "Exclusive Deal – 50% Off for 24 Hours!",
marginRight: "10px",
borderRadius: "5px",
width: "100%",
height: "50px",
startDate: "2024-12-24T00:00:00", //Update with the correct values before implementation
endDate: "2024-12-25T23:59:59", //Update with the correct values before implementation
backgroundColor: "#970747",
titleColor: "#ffffff",
};
const isAnnouncementActive = (startDate, endDate) => {
const now = new Date();
const start = new Date(startDate);
const end = new Date(endDate);
return now >= start && now <= end;
};
const displayAnnouncementBanner = (data) => {
const container = document.getElementById('announcement-banner');
if (!container) {
console.error('Container for the announcement banner not found.');
return;
}
if (container.querySelector('.announcement-content')) {
console.log('Announcement already present. Skipping rendering.');
return;
}
if (isAnnouncementActive(data.startDate, data.endDate)) {
const announcement = document.createElement('div');
announcement.classList.add('announcement-content');
announcement.innerText = data.title;
announcement.style.marginRight = data.marginRight;
announcement.style.borderRadius = data.borderRadius;
announcement.style.width = data.width;
announcement.style.height = data.height;
announcement.style.backgroundColor = data.backgroundColor;
announcement.style.color = data.titleColor;
announcement.style.display = "flex";
announcement.style.alignItems = "center";
announcement.style.justifyContent = "center";
announcement.style.boxShadow = "0px 4px 6px rgba(0, 0, 0, 0.1)";
announcement.style.padding = "10px";
announcement.style.border = "1px solid black";
announcement.style.fontWeight = "bold";
announcement.style.fontSize = "16px";
container.appendChild(announcement);
console.log('Announcement banner rendered.');
} else {
console.log('Announcement is not active at this time.');
}
};
const container = document.getElementById('announcement-banner');
if (container) {
var observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
console.log('Mutation detected:', mutation);
});
displayAnnouncementBanner(announcementData);
});
observer.observe(container, { childList: true });
setTimeout(() => {
observer.disconnect();
console.log('Observer disconnected to prevent infinite loop.');
}, 1000);
}
setInterval(() => {
const container = document.getElementById('announcement-banner');
if (container && !container.querySelector('.announcement-content')) {
console.log('Announcement missing. Re-rendering.');
displayAnnouncementBanner(announcementData);
}
}, 5000);
displayAnnouncementBanner(announcementData);
});
</script>
<div id="announcement-banner" style="border: 1px solid red;"></div>
Please read the explanation section to understand how the wrapper code works.
- Select Allow on all pages checkbox if want to show the bannner in all the pages.
- Select where you need to show the product highlight from the dropdown list.
- Click Add.
You will see a success notification when the Bindings are successfully created.
Apply Bindings to Theme
Once you've created the ScriptTag Binding, you need to add it to the storefront. In this example, we will add the announcement banner to the header.
- Login to Fynd Commerce.
- Navigate to the desired sales channel.
- Go to Appearance → Themes.
- Navigate to the theme where you need to add the announcement banner and click Edit. The Theme Editor page opens.
- In the left pane, go to Settings → Header Bindings.
- Click + Add Section and navigate to Extension.
- In the Extensions section, click Add.
- Choose the Extension for which you have created the Bindings.
- Select the Binding you created in the previous step.
- Click Save.
- Verify that the announcement banner appears in the correct position on the storefront.
Test the Banner
You have successfully embedded an announcement banner inside the header of your theme using ScriptTag Binding.
A Deep Dive into Wrapper Code
Announcement Data
const announcementData = {
title: "Flash Sale - Up to 50% Off!",
marginRight: "10px",
borderRadius: "5px",
width: "100%",
height: "50px",
startDate: "2024-12-23T00:00:00", //Update with the correct values before implementation
endDate: "2025-12-24T23:59:59", //Update with the correct values before implementation
backgroundColor: "#f8d7da",
titleColor: "#721c24",
};
- This object contains the properties required to configure the announcement banner, such as:
title
: The announcement text.startDate
andendDate
: The period when the announcement should be active.- Styling properties:
backgroundColor
,titleColor
,width
,height
, etc.
Check if the Announcement is Active
The isAnnouncementActive
function compares the current date and time against the provided boundaries (startDate
and endDate
) and ensures that the banner is displayed only during the given sale period.
- If the current date is equal to or lies between
startDate
andendDate
, the function returnstrue
, signaling that the announcement should be shown. - If the current date falls outside this range, it returns
false
, suppressing the announcement.
const isAnnouncementActive = (startDate, endDate) => {
const now = new Date();
const start = new Date(startDate);
const end = new Date(endDate);
return now >= start && now <= end;
};
Display the Banner
The displayAnnouncementBanner
function ensures the existence of the #announcement-banner
in the DOM and checks if an announcement is already present by looking for .announcement-content
. If an announcement exists, it skips rendering to prevent duplication. If not, it forms the announcement banner by creating a div
element and applying styles and text from announcementData
. Finally, it appends this newly created announcement to the #announcement-banner
container.
const displayAnnouncementBanner = (data) => {
const container = document.getElementById("announcement-banner");
if (!container) {
console.error("Container for the announcement banner not found.");
return;
}
if (container.querySelector(".announcement-content")) {
console.log("Announcement already present. Skipping rendering.");
return;
}
if (isAnnouncementActive(data.startDate, data.endDate)) {
const announcement = document.createElement("div");
announcement.classList.add("announcement-content");
announcement.innerText = data.title;
// Apply styles
announcement.style.marginRight = data.marginRight;
announcement.style.borderRadius = data.borderRadius;
announcement.style.width = data.width;
// ...
announcement.style.fontSize = "16px";
container.appendChild(announcement);
console.log("Announcement banner rendered.");
} else {
console.log("Announcement is not active at this time.");
}
};
Mutation Observer
This function monitors the #announcement-banner
for changes to its child elements, such as additions or removals of content. If any modifications are detected, it triggers displayAnnouncementBanner
to ensure the announcement is re-rendered if necessary. To avoid an infinite loop from continuous DOM updates, the observer automatically disconnects after one second, ensuring efficient and controlled handling of DOM changes.
var observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
console.log("Mutation detected:", mutation);
});
displayAnnouncementBanner(announcementData);
});
observer.observe(container, { childList: true });
setTimeout(() => {
observer.disconnect();
console.log("Observer disconnected to prevent infinite loop.");
}, 1000);
Periodic Check with setInterval
This mechanism ensures the announcement banner is consistently displayed, even if an external script accidentally removes the #announcement-banner
. Checking every five seconds for the presence of .announcement-content
within the container guarantees that the announcement remains visible. If the content is missing, the function calls displayAnnouncementBanner
to recreate and restore the announcement banner, maintaining uninterrupted communication with users.
setInterval(() => {
const container = document.getElementById("announcement-banner");
if (container && !container.querySelector(".announcement-content")) {
console.log("Announcement missing. Re-rendering.");
displayAnnouncementBanner(announcementData);
}
}, 5000);
Initial Render
The displayAnnouncementBanner
function is called to ensure that the announcement is displayed immediately when the page loads.
displayAnnouncementBanner(announcementData);
Add the Container
The HTML element with the id announcement-banner
is added at the end.
<div id="announcement-banner" style="border: 1px solid red;"></div>