How To
Compare Products on Results Page
7min
overview of customization modify 3 template js templates to add compare feature klevutemplatelanding add a table to display compared products filters to display selected products to compare productblock add compare toggle to each product add javascript to power the compare feature set attributes to display for compare tell klevu to override default templates powerup code for compare feature add css to style the compare feature requirements you must have klevu integrated in your store using template js you need the ability to modify the code in your store compare feature will be added to the search result landing page and category pages add custom template code add the following code anywhere on your store this code only needs to be loaded on the pages where the compare feature will be present, so you may conditionally add this code only when these pages are accessed if you already have custom templates for klevutemplatelanding , filters , and/or productblock , we have added comments to show what code is necessary \<script type="template/klevu" id="klevulandingtemplatebasecustom"> \<div ku container data container id="ku landing main container" data container role="main"> \<header ku container data container id="ku landing main header container" data container role="header"> \<section ku block data block id="ku landing main header sub panel">\</section> \<section ku block data block id="ku landing main header banner"> <%=helper render('klevulandingpromotionbanner',scope,data,"top") %> <%=helper render('klevulandingpromotionbanner',scope,data,"bottom") %> \</section> \<section ku block data block id="ku landing main header site navigation">\</section> \</header> \<div class="kucontainer"> <% if(!helper hasresults(data,"productlist") && !helper hasfilters(data,"productlist")) { %> <%=helper render('noresultsfoundlanding',scope) %> <% } else { %> <%= helper render('klevulandingtemplatesearchbar', scope) %> <%=helper render('klevulandingimagesearchuploadbanner',scope,data) %> <%= helper render('tab results', scope) %> <%= helper render('results',scope) %> <% } %> \<div class="kuclearboth">\</div> \</div> \<footer ku container data container id="ku landing main footer container" data container role="footer"> \<section ku block data block id="ku landing main footer sub panel">\</section> \<section ku block data block id="ku landing main footer banner"> \</section> \</footer> \</div> \<! start of compare customization > \<div class="klevu compare table" id="klevu compare table"> \<table class="klevu compare table products"> \<div class="klevu compare table header"> \<label class="toggle differences">\<input type="checkbox" id="toggledifferences" <% if (klevu compare show differences checked) { %>checked<% } %> /><%= helper translate("show only differences")%>\</label> \<button id="klevu close compare"> \<svg style="pointer events\ none;" enable background="new 0 0 386 667 386 667" height="15" viewbox="0 0 386 667 386 667" width="15"> \<path d="m386 667 45 564 45 564 45 564 147 77 147 769 147 769 147 769 45 564 45 564 147 769 147 769 147 769 147 77 45 564 45 564 147 769 147 769 147 769 147 769 45 564 45 564 147 768 147 77z"/> \</svg> \</button> \</div> \<thead> \<tr> \<th class="klevu compare table label">\</th> \<th>\<img src="" alt="">\<span>\</span>\</th> \</tr> \</thead> \<tbody> \<tr> \<td class="klevu compare table label">label\</td> \<td>\<div class="spec" spec title="label">\</div>\</td> \</tr> \</tbody> \</table> \</div> \<! end of compare customization > \</script> \<script type="template/klevu" id="klevulandingtemplatefilterscustom"> <% if(data query\[datalocal] filters length > 0 ) { %> \<div class="kufilters" role="navigation" data position="left" aria label="product filters" tabindex="0"> \<! start of compare customization > \<div class="klevu compare widget klevu compare widget klevu hidden" id="klevu compare widget"> \<ul class="klevu compare widget images">\</ul> \<div class="klevu compare widget header"> \<span><%= helper translate("to compare")%>\<span class="klevu compare widget selected amount">\</span>\</span> \<button id="klevu compare button" type="button" disabled><%= helper translate("compare")%>\</button> \</div> \</div> \<! end of compare customization > \<h3 class="kufilterstitleheading"><%=helper translate("narrow by")%>\</h3> <% helper each(data query\[datalocal] filters,function(key,filter){ %> <% if(filter type == "options"){ %> \<div class="kufilterbox klevufilter <%=(filter multiselect)?'kumulticheck' ''%>" data filter="<%=filter key%>" <% if(filter multiselect){ %> data singleselect="false" <% } else { %> data singleselect="true"<% } %>> \<div class="kufilterhead <%=(filter iscollapsed) ? 'kuexpand' 'kucollapse'%>"> <% var filter label = (filter label=="klevu price") ? "price" filter label; %> <%=helper translate(filter label)%> \</div> \<div data optioncount="<%= filter options length %>" class="kufilternames <%= (filter options length <= 5 ) ? 'kufiltershowall' '' %> <%=(filter iscollapsed) ? 'kufiltercollapse' ''%>"> \<ul> <% helper each(filter options,function(key,filteroption){ %> \<li <% if(filteroption selected ==true) { %> class="kuselected"<% } %>> \<a target=" self" href="#" title="<%=helper escapehtml(filteroption name)%>" class="klevufilteroption<% if(filteroption selected ==true) { %> klevufilteroptionactive<% } %>" data value="<%=helper escapehtml(filteroption value)%>" data name="<%=helper escapehtml(filteroption name)%>" \> \<span class="kufiltericon">\</span> \<span class="kufacet text"><%=filteroption name%>\</span> <% if(filteroption selected ==true) { %> \<span class="kufiltercancel">x\</span> <% } else { %> \<span class="kufiltertotal"><%=filteroption count%>\</span> <% } %> \</a> \</li> <% }); %> \</ul> <% if(filter options length > 5 ) { %> \<div class="kushowopt" tabindex=" 1"> \<span class="kufilterdot">\</span>\<span class="kufilterdot">\</span>\<span class="kufilterdot">\</span> \</div> <% } %> \</div> \</div> <% } else if(filter type == "slider") { %> \<div class="kufilterbox klevufilter" data filter="<%=filter key%>"> \<div class="kufilterhead <%=(filter iscollapsed) ? 'kuexpand' 'kucollapse'%>"> <% var filter label = (filter label=="klevu price") ? "price" filter label; %> <%=helper translate(filter label)%> \</div> \<div class="kufilternames sliderfilternames <%=(filter iscollapsed) ? 'kufiltercollapse' ''%>"> \<div class="kupriceslider klevusliderfilter" data query = "<%=datalocal%>"> \<div data querykey = "<%=datalocal%>" class="noui target noui ltr noui horizontal noui background kusliderfilter kupricerangesliderfilter<%=datalocal%>">\</div> \</div> \</div> \</div> <% } else if (filter type == "rating") { %> \<div class="kufilterbox klevufilter <%=(filter multiselect)?'kumulticheck' ''%>" data filter="<%=filter key%>" <% if(filter multiselect){ %> data singleselect="false" <% } else { %> data singleselect="true"<% } %>> \<div class="kufilterhead <%=(filter iscollapsed) ? 'kuexpand' 'kucollapse'%>"> <%=helper translate(filter label)%> \</div> \<div data optioncount="<%= filter options length %>" class="kufilternames <%= (filter options length <= 5 ) ? 'kufiltershowall' '' %> <%=(filter iscollapsed) ? 'kufiltercollapse' ''%>"> \<ul> <% helper each(filter options,function(key,filteroption){ %> \<li <% if(filteroption selected ==true) { %> class="kuselected"<% } %>> \<a target=" self" href="#" title="<%=helper escapehtml(filteroption name)%>" class="klevufilteroption<% if(filteroption selected ==true) { %> klevufilteroptionactive<% } %>" data value="<%=helper escapehtml(filteroption value)%>" data name="<%=helper escapehtml(filteroption name)%>" \> \<span class="kufiltericon">\</span> \<span class="kufacet text"> \<div class="klevufacetstars"> \<div class="klevufacetrating" style="width <%=(20 number(filteroption name))%>%;">\</div> \</div> \</span> <% if(filteroption selected ==true) { %> \<span class="kufiltercancel">x\</span> <% } else { %> \<span class="kufiltertotal"><%=filteroption count%>\</span> <% } %> \</a> \</li> <% }); %> \</ul> \</div> \</div> <% } else { %> \<! other facets > <% } %> <% }); %> \<! \<div class="kufiltersfooter"> \<a target=" self" href="javascript\ void(0)" class="kubtn kufacetsslideout kumobilefilterclosebtn" role="button" tabindex="0" area label=""><%=helper translate("close")%>\</a> \</div> > \</div> <% } %> \</script> \<script type="template/klevu" id="klevulandingtemplateproductblockcustom"> <% var updatedproductname = datalocal name; if(klevu search modules kmcinputs base getskuonpageenablevalue()) { if(klevu dom helpers cleanupsku(datalocal sku)) { updatedproductname += klevu dom helpers cleanupsku(datalocal sku); } } %> \<li ku product block class="klevuproduct" data id="<%=datalocal id%>"> \<div class="kuprodwrap"> \<header ku block data block id="ku landing result item header"> <%=helper render('landingproductbadge', scope, data, datalocal) %> \</header> <% var desc = \[datalocal summaryattribute,datalocal packagetext,datalocal summarydescription] filter(function(el) { return el; }); desc = desc join(" "); %> \<main ku block data block id="ku landing result item info"> \<div class="kuprodtop"> \<div class="klevuimgwrap"> \<a data id="<%=datalocal id%>" href="<%=datalocal url%>" class="klevuproductclick kutrackrecentview"> \<img src="<%=datalocal image%>" origin="<%=datalocal image%>" onerror="klevu dom helpers cleanupproductimage(this)" alt="<%=updatedproductname%>" class="kuprodimg"> <%=helper render('landingimagerollover', scope, data, datalocal) %> \</a> \</div> \<! \<div class="kuquickview"> \<button data id="<%=datalocal id%>" class="kubtn kubtnlight kuquickviewbtn" role="button" tabindex="0" area label="">quick view\</button> \</div> > \</div> \</main> \<footer ku block="" data block id="ku landing result item footer"> \<div class="kuprodbottom"> \<div class="kuname kuclippedone">\<a data id="<%=datalocal id%>" href="<%=datalocal url%>" class="klevuproductclick kutrackrecentview" title="<%= updatedproductname %>"><%= updatedproductname %>\</a>\</div> <% if(datalocal instock && datalocal instock != "yes") { %> <%=helper render('landingproductstock', scope, data, datalocal) %> <% } else { %> <% if(klevu search modules kmcinputs base getshowprices()) { %> \<div class="kuprice"> <% var kutotalvariants = klevu dom helpers cleanuppricevalue(datalocal totalvariants); var kustartprice = klevu dom helpers cleanuppricevalue(datalocal startprice,datalocal currency); var kusaleprice = klevu dom helpers cleanuppricevalue(datalocal saleprice,datalocal currency); var kuprice = klevu dom helpers cleanuppricevalue(datalocal price,datalocal currency); %> <% if(!number isnan(kutotalvariants) && !number isnan(kustartprice)) { %> \<div class="kusaleprice kustartprice kuclippedone"> \<span class="klevuquickpricegreytext"><%=helper translate("starting at")%>\</span> \<span><%=helper processcurrency(datalocal currency,parsefloat(datalocal startprice))%>\</span> \</div> <% } else if(!number isnan(kusaleprice) && !number isnan(kuprice) && (kuprice > kusaleprice)){ %> \<span class="kuorigprice kuclippedone"> <%= helper processcurrency(datalocal currency,parsefloat(datalocal price)) %> \</span> \<span class="kusaleprice kuspecialprice kuclippedone"> <%=helper processcurrency(datalocal currency,parsefloat(datalocal saleprice))%> \</span> <% } else if(!number isnan(kusaleprice)) { %> \<span class="kusaleprice kuspecialprice"> <%= helper processcurrency(datalocal currency,parsefloat(datalocal saleprice)) %> \</span> <% } else if(!number isnan(kuprice)) { %> \<span class="kusaleprice"> <%= helper processcurrency(datalocal currency,parsefloat(datalocal price)) %> \</span> <% } %> <%=helper render('searchresultproductvatlabel', scope, data, datalocal) %> \</div> <% } %> <% } %> \</div> \<div class="kuprodadditional"> \<div class="kuprodadditionaldata"> <% if(desc && desc length) { %> \<div class="kudesc kuclippedtwo"> <%=desc%> \</div> <% } %> <%=helper render('landingproductswatch',scope,data,datalocal) %> <%=helper render('klevulandingproductrating',scope,data,datalocal) %> <% var isaddtocartenabled = klevu search modules kmcinputs base getaddtocartenablevalue(); %> <% if(isaddtocartenabled) { %> <%=helper render('landingpageproductaddtocart',scope,data,datalocal) %> <% } %> \</div> \</div> \</footer> \</div> \<! start of compare customization > \<button class="klevu compare" data id="<%=datalocal id%>" data itemgroupid="<%=datalocal itemgroupid%>"> \<input id="klevucompare <%=datalocal id%>" class="klevu compare checkbox" type="checkbox" style="pointer events\ none"/> \<label for="klevucompare <%=datalocal id%>" class="klevu compare label"> <%= helper translate("compare")%> \</label> \</button> \<! end of compare customization > \</li> \</script> add javascript code first, let’s add the code that will choose which attributes to callout when products are compared // array of keys you want to render in the compare table window\ keys to compare = \[ "instock", "grams", "sku", "brand", "size", "category" // "tags", // "type", // "itemgroupid", // "storebasecurrency", // "inventory item id", // "imageurl", // "currency", // "id", // "image", // "url", // "product type", // "name", // "shortdesc", ]; next we need to tell klevu to use our custom templates skip this step if you are already customizing all three of these templates ( klevutemplatelanding , filters , and productblock) you may need to modify the code if you only have one or two of these templates klevu({ theme { settemplates { comparebase { scope "landing,catnav", selector "#klevulandingtemplatebasecustom", name "klevutemplatelanding" }, comparefilters { scope "landing,catnav", selector "#klevulandingtemplatefilterscustom", name "filters" }, compareproductblock { scope "landing,catnav", selector "#klevulandingtemplateproductblockcustom", name "productblock" } } } }); now we need to add the code that will powerup the compare feature // this settings controls whether to show only differences on page load or not window\ klevu compare show differences checked = true; klevu aftertemplaterender('landing,catnav', function(data, scope){ / compare products feature / const docbody = document getelementsbytagname('body')\[0]; const klevuapikey = klevu getglobalsetting("search apikey", klevu getglobalsetting("global apikey")); const placeholderimageurl = 'https //js klevu com/klevu js v1/img 1 1/place holder jpg'; // replace with your placeholder image url const klevuscope = klevu getsetting(klevu, "settings flags setremoteconfiglanding build") ? 'landing' 'catnav'; togglecheckbox(); savecomparedatatolocalstorage(); \[ document queryselectorall(' klevu compare')] foreach(element => { klevu event attach(element, "click", clickhandler addtocomparelist); }); docbody addeventlistener('click', function ({ target }) { try { if (target matches('#klevu compare button, #klevu compare button , #klevu compare table, #klevu compare table ')) { docbody classlist add('klevu compare table shown'); } else { docbody classlist remove('klevu compare table shown'); } // close button if (target matches("#klevu close compare, #klevu close compare ")) { docbody classlist remove('klevu compare table shown'); } } catch (err) { } }) function getklevucompareidarray() { return localstorage getitem(`klevu compare ids ${klevuscope} ${klevuapikey}`) ? json parse(localstorage getitem(`klevu compare ids ${klevuscope} ${klevuapikey}`)) \[]; } function saveidstolocalstorage(currid, forceoverride = false) { if (forceoverride) { // save the updated data back to local storage localstorage setitem(`klevu compare ids ${klevuscope} ${klevuapikey}`, json stringify(currid)); } else { let existingids = getklevucompareidarray(); if (!getklevucompareidarray() includes(currid)) { // check if the id is not already in the existing data existingids push(currid); // add the new id to the existing data } else if (getklevucompareidarray() includes(currid)) { const existingindex = getklevucompareidarray() indexof(currid); existingids splice(existingindex, 1); // remove this id from the existing data } // save the updated data back to local storage localstorage setitem(`klevu compare ids ${klevuscope} ${klevuapikey}`, json stringify(existingids)); } }; function savecomparedatatolocalstorage(data = null) { localstorage setitem(`klevu compare data ${klevuscope} ${klevuapikey}`, data); // if no argument passed && there are some ids in the storage, but no entries in local storage if (data === null && getklevucompareidarray() && !getklevucomparedataobject()) { getandsavedatabyids(getklevucompareidarray()); } } function getklevucomparedataobject() { return json parse(localstorage getitem(`klevu compare data ${klevuscope} ${klevuapikey}`)) } function clearimgurl(url) { return url replace("/needtochange/", "/") }; function rendersidewidget() { const selectedproductsamount = getklevucompareidarray() length || null; const widgetelement = document queryselector('#klevu compare widget'); const widgetcomparebuttonelement = document queryselector('#klevu compare button'); const selectedproductsamountelement = document queryselector(' klevu compare widget selected amount'); const selectedproductsimageselement = document queryselector(' klevu compare widget images'); let widgethtmllistitem = ''; getklevucomparedataobject() map(item => { const imageurl = item image ? clearimgurl(item image) placeholderimageurl; widgethtmllistitem += ` \<li class="klevu compare widget item"> \<button class="klevu compare widget item button" data id="${item id}" title="remove from klevu comparison"> \<img class="klevu compare widget item image" alt="${item name}" style="max height 50px;max width 40px;" src="${imageurl}" onerror="this onerror=null; this src='${placeholderimageurl}'" /> \<i class="klevu compare widget item button cross">\×\</i> \</button> \</li>`; selectedproductsimageselement innerhtml = widgethtmllistitem; }); if (selectedproductsamount && widgetelement) { selectedproductsamountelement innerhtml = selectedproductsamount; selectedproductsimageselement innerhtml = widgethtmllistitem; widgetelement classlist remove('klevu compare widget klevu hidden'); if (selectedproductsamount > 1) { widgetcomparebuttonelement disabled = false; } else { widgetcomparebuttonelement disabled = true; } } else if (widgetelement) { widgetelement classlist add('klevu compare widget klevu hidden'); } } function generateaddtocarthtml(item) { // check if the item is in stock if (item instock !== "no") { // get the 'add to cart' caption var addtocartcaption = klevu getobjectpath(klevu search, "modules kmcinputs kmcdata klevu uc useroptions addtocartbutton", "add to cart"); var translatedcaption; if (typeof klevu uc useroptions !== 'undefined' && klevu uc useroptions) { translatedcaption = klevu uc useroptions addtocartbutton; } // check if the 'add to cart' caption contains an image if (addtocartcaption) { return ` \<div class="kuaddtocart" data id="${item id}"> \<a target=" self" href="javascript\ void(0)" class="kubtn kubtndark kulandingaddtocartbtn" role="button" tabindex="0" aria label="add to cart">${addtocartcaption}\</a> \</div> `; } } return ''; } function generatepricehtml(data) { var kutotalvariants = klevu dom helpers cleanuppricevalue(data totalvariants); var kustartprice = klevu dom helpers cleanuppricevalue(data startprice, data currency); var kusaleprice = klevu dom helpers cleanuppricevalue(data saleprice, data currency); var kuprice = klevu dom helpers cleanuppricevalue(data price, data currency); var processcurrency = scope kscope template gettemplatesettings() helpers processcurrency; let htmlparts = \['']; if (!isnan(kutotalvariants) && !isnan(kustartprice)) { htmlparts push(` \<div class="kusaleprice kustartprice kuclippedone"> \<span class="klevuquickpricegreytext">starting at\</span> \<span>${processcurrency(data currency, parsefloat(data startprice))}\</span> \</div>`); } else if (!isnan(kusaleprice) && !isnan(kuprice) && (kuprice > kusaleprice)) { htmlparts push(` \<span class="kuorigprice kuclippedone"> ${processcurrency(data currency, parsefloat(data price))} \</span> \<span class="kusaleprice kuspecialprice kuclippedone"> ${processcurrency(data currency, parsefloat(data saleprice))} \</span>`); } else if (!isnan(kusaleprice)) { htmlparts push(` \<span class="kusaleprice kuspecialprice"> ${processcurrency(data currency, parsefloat(data saleprice))} \</span>`); } else if (!isnan(kuprice)) { htmlparts push(` \<span class="kusaleprice"> ${processcurrency(data currency, parsefloat(data price))} \</span>`); } htmlparts push(''); return htmlparts join(''); } function rendercompareproducts() { const selectedproductsamount = getklevucompareidarray() length || null; const tableelement = document queryselector('#klevu compare table'); const tableheadelement = tableelement queryselector('thead tr'); const tableoptionelement = tableelement queryselector('tbody'); let listitemheadinghtml = ``; let listitemoptionhtml = ``; getklevucomparedataobject() foreach(item => { const imageurl = item image ? clearimgurl(item image) placeholderimageurl; listitemheadinghtml += `\<th> \<img src="${imageurl}" alt="${item name}"> \<div class="kuname kuclippedone"> \<a data id="${item id}" href="${item url}" class="klevuproductclick" title="${item name}">${item name}\</a> \</div> \<div class="kuprice">${generatepricehtml(item)}\</div> \<button class="klevu compare widget item button" data id="${item id}" title="remove from klevu comparison">\<span>\×\</span>\</button> ${generateaddtocarthtml(item)} \</th>`; }); try { keys to compare foreach(key => { // map out the values for this key from each product const values = getklevucomparedataobject() map(item => item\[key] || ''); // check if all values are the same, ignoring case const allvaluessame = values every((val, , arr) => val tolowercase() === arr\[0] tolowercase()); // determine whether to add the 'hide' class based on the comparison const trclass = allvaluessame && klevu compare show differences checked ? 'hide' ''; const valuerows = values map(value => `\<td>\<span class="spec" spec title="${key}">${value}\</span>\</td>`) join(''); if (valuerows trim()) { // only add the row if it's not empty listitemoptionhtml += `\<tr class="${trclass}" data name="${key}">\<td class="klevu compare table label">${key}\</td>${valuerows}\</tr>`; } }); } catch (error) { console log('keys to compare array error please declare the keys to compare array!', error); } tableheadelement innerhtml = `\<th class="klevu compare table label">\ \</th> ${listitemheadinghtml}`; tableoptionelement innerhtml = listitemoptionhtml; if (selectedproductsamount) { // add code for displaying the selected products amount } else { // add code for handling no selected products } } function toggledifferences() { const toggledifferencescheckbox = document getelementbyid('toggledifferences'); toggledifferencescheckbox addeventlistener('change', function () { const rows = document queryselectorall('#klevu compare table tbody tr'); rows foreach(row => { const values = \[ row\ queryselectorall('td span spec')] map(spec => spec textcontent trim() tolowercase()); const allequal = values every(val => val === values\[0]); if (allequal) { row\ classlist toggle('hide', this checked); } }); }); } function rendercomparewidget() { rendersidewidget(); rendercompareproducts(); toggledifferences(); } function getandsavedatabyids(idarray) { / send request get products by ids / const idquerystring = `(${idarray map(id => `id "${id}"`) join(" or ")})`; var data = json stringify({ recordqueries \[ { settings { customandquery idquerystring, query { term " " }, typeofrecords \["klevu product"], fields \[], limit idarray length, }, id "productsearch", }, ], context { apikeys \[klevuapikey] }, }); var xhr = new xmlhttprequest(); xhr withcredentials = false; xhr addeventlistener("readystatechange", function () { if (this readystate === 4) { const results = json parse(this responsetext) queryresults\[0] records; fireafterrequest(results); } }); xhr open("post", klevu settings url search); xhr setrequestheader("content type", "application/json"); xhr send(data); // send the request } function togglecheckbox(currentid = null) { try { if (currentid) { // on click if (getklevucompareidarray() includes(currentid)) { document queryselector(` klevu compare\[data id="${currentid}"]`) classlist add('klevu selected'); document queryselector(` klevu compare\[data id="${currentid}"] input`) checked = true; } else { document queryselector(` klevu compare\[data id="${currentid}"]`) classlist remove('klevu selected'); document queryselector(` klevu compare\[data id="${currentid}"] input`) checked = false; } } else { // on load \[ document queryselectorall(' klevu compare')] foreach(element => { // if (getklevucompareidarray() includes(element dataset itemgroupid)) { if (getklevucompareidarray() includes(element dataset id)) { element classlist add('klevu selected'); element queryselector('input klevu compare checkbox') checked = true; } }); } } catch (error) { } } function removefromklevucomparison(id) { \[ document queryselectorall(' klevu compare widget item button')] foreach(element => { element addeventlistener('click', function (ev) { ev preventdefault(); ev stoppropagation(); // const currid = ev target closest(' klevu compare widget item button') dataset itemgroupid; const currid = ev target closest(' klevu compare widget item button') dataset id; const filtereddata = getklevucompareidarray() filter(val => val !== currid); saveidstolocalstorage(filtereddata, true); getandsavedatabyids(getklevucompareidarray()); togglecheckbox(currid); // hide compare popup if there's 1 product if (getklevucompareidarray() length <= 1) { docbody classlist remove('klevu compare table shown'); } }) }); } function clickhandler addtocomparelist(event) { // const currentid = event target closest(' klevu compare') dataset itemgroupid; const currentid = event target closest(' klevu compare') dataset id; event stoppropagation(); event preventdefault(); saveidstolocalstorage(currentid); togglecheckbox(currentid); getandsavedatabyids(getklevucompareidarray()); // rendercomparewidget(); } function fireafterrequest(results) { savecomparedatatolocalstorage(json stringify(results)); rendercomparewidget(); removefromklevucomparison(); } / end of compare products feature / }); add css code the final step is to add the css code that will style the compare feature \<style> / compare feature / kusearchresultspagecontainer \[ku container] klevu compare, kusearchresultspagecontainer klevu compare { display flex; justify content center; align content center; position absolute; top 0; right 0; z index 2; background color #fff; padding 3px 15px; display flex; justify content center; align items center; border 1px solid var( klevu bgcolor); border radius var( klevu buttonradius); } kusearchresultspagecontainer \[ku container] #klevu compare button, kusearchresultspagecontainer #klevu compare button { color #fff; cursor pointer; background color var( klevu blue); border 0; padding 5px 8px; } kusearchresultspagecontainer \[ku container] #klevu compare button\ disabled, kusearchresultspagecontainer #klevu compare button\ disabled { cursor no drop; opacity 0 5; } kusearchresultspagecontainer \[ku container] klevu compare checkbox, kusearchresultspagecontainer klevu compare checkbox { margin 0; } kusearchresultspagecontainer \[ku container] klevu compare label, kusearchresultspagecontainer klevu compare label { margin left 5px; cursor pointer; } kusearchresultspagecontainer \[ku container] div klevu compare widget selected amount before { content ' '; margin left 0; margin right 5px; } kusearchresultspagecontainer \[ku container] div #klevu compare widget { display flex; flex direction column; gap 10px; margin 10px auto; } kusearchresultspagecontainer \[ku container] div klevu compare widget header { display flex; flex direction column; gap 10px; } kusearchresultspagecontainer \[ku container] div klevu compare widget images { display flex; align items center; gap 0 10px; margin 0; padding 0; overflow x auto; } kusearchresultspagecontainer \[ku container] div klevu compare widget item { list style none; border 1px solid transparent; } kusearchresultspagecontainer \[ku container] div klevu compare widget item\ hover { list style none; border 1px solid #888; } kusearchresultspagecontainer \[ku container] div klevu compare widget item button { border 0; background color transparent; padding 0; margin 0; cursor pointer; position relative; } kusearchresultspagecontainer \[ku container] div klevu compare widget item button cross { position absolute; font style normal; top 5px; right 0; } kusearchresultspagecontainer #klevu close compare { background color #fff; border 0; padding 15px; cursor pointer; z index 1; border 1px solid transparent; display flex; align items center; justify content center; } kusearchresultspagecontainer #klevu close compare\ hover { border 1px solid var( klevu black) } kusearchresultspagecontainer #klevu compare table tr { display grid; grid auto flow column; grid auto columns 1fr; } kusearchresultspagecontainer #klevu compare table thead { position sticky; top 0; } kusearchresultspagecontainer #klevu compare table tr th klevu compare widget item button { position absolute; top 0; right 0; background color var( klevu blue); color #fff; border 0; } kusearchresultspagecontainer \[ku container] div #klevu compare widget klevu compare widget klevu hidden { display none; visibility hidden; } kusearchresultspagecontainer klevu compare table { display none; visibility hidden; background #fff; max height calc(100vh 10%); overflow auto; position fixed; top 50%; left 50%; transform translate( 50%, 50%); max width 85vw; z index 1000; } body klevu compare table shown kusearchresultspagecontainer klevu compare table { display block; visibility visible; } body klevu compare table shown kusearchresultspagecontainer \[data container role=main] kucontainer { filter blur(3px); } body klevu compare table shown kusearchresultspagecontainer klevuwrap before { background color #000; opacity 0 5; width 100vw; height 100vh; position fixed; top 0; left 0; right 0; bottom 0; display block; content ''; z index 1; } kusearchresultspagecontainer klevu compare table table {} kusearchresultspagecontainer klevu compare table th { position sticky; / make th sticky to avoid javascript / z index 1; / border 1px solid #ccc; / top 0; display flex; flex direction column; align items center; justify content center; } kusearchresultspagecontainer klevu compare table th\ not(\ last child), kusearchresultspagecontainer klevu compare table td\ not(\ last child) { border right 1px solid #ccc; } kusearchresultspagecontainer klevu compare table td, kusearchresultspagecontainer klevu compare table th { padding 10px; min width 300px; / add a minimum width below which no resize is allowed (for small screens) it can be whatever serves the design best / text align center; } kusearchresultspagecontainer klevu compare table klevu compare table products { / padding top 40px; / max height calc(100vh 10%); overflow auto; padding 15px; } kusearchresultspagecontainer klevu compare table klevu compare table products th, kusearchresultspagecontainer klevu compare table klevu compare table products td { width 25%; max width 300px; overflow hidden; gap 10px 0; / depending on the number of products in comparison, different classes should be used (e g 3 products should have a products 3 class with a width of 33 333%) / } kusearchresultspagecontainer klevu compare table th { background #fff; / top 2px; / top 0; / we need this to attach the "stuck" attribute / } kusearchresultspagecontainer klevu compare table th h4 { margin 15px 0 0; } kusearchresultspagecontainer klevu compare table th img { max height calc(var( klevu product image height desktop) 50px) !important; max width 100%; object fit contain; margin 0 auto; display block; transition height 200ms ease in out; } kusearchresultspagecontainer klevu compare table th kuname { display block !important; } kusearchresultspagecontainer klevu compare table th kuprice { margin top auto; text align center; } kusearchresultspagecontainer klevu compare table th kubtn, kusearchresultspagecontainer klevu compare table th kuaddtocart { margin 0; } kusearchresultspagecontainer klevu compare table klevu compare table sticky img { height 100px; } kusearchresultspagecontainer klevu compare table klevu compare table label { font weight bold; text align left; min width 150px; / labels should have a strict width, based on the design (150px is just for this demo) / width 150px; / in order to enforce the width we need to apply both a min width and a width with the same value / background #eee; } kusearchresultspagecontainer klevu compare table th klevu compare table label { background #fff; border color #fff; } kusearchresultspagecontainer klevu compare table klevu compare table heading { background #ccc; width 100%; text align left; position relative; } kusearchresultspagecontainer klevu compare table klevu compare table heading span { position sticky; top 0; left 10px; } kusearchresultspagecontainer klevu compare table spec { word break break all; } kusearchresultspagecontainer #klevu compare table hide { display none; visibility hidden; } kusearchresultspagecontainer #klevu compare table klevu compare table header { z index 2; background color #fff; position sticky; top 0; right 0; left 0; display flex; justify content space between; align items center; padding 15px; } kusearchresultspagecontainer #klevu compare table toggle differences { position sticky; top 5px; left 5px; padding 10px 15px; border 1px solid var( klevu black); } / @media all and (max width 600px) { / kusearchresultspagecontainer klevu compare table klevu compare table label { display none; / we want to hide the labels on small screens / } kusearchresultspagecontainer klevu compare table spec before { / and show them above each spec instead / content attr(spec title); color #999; display block; text transform capitalize; } / compare feature end / \</style>