# Time calculation feature

**URL:** <https://community.elfsight.com/t/time-calculation-feature/139487>\
**Category:** Calculator\
**Tags:** Gathering-Feedback\
**Created:** [September 9, 2025, 6:41pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487 "2025-09-09T18:41:59Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 9, 2025, 6:41pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/1 "2025-09-09T18:41:59Z")

</div>

Currently, I have a cleaning cost calculator that estimates the price based on the home’s size, number of bedrooms, bathrooms, and other parameters. After entering all the details, the client receives a cost estimate. However, in most cases, clients also want to know **how long the cleaning will take**. I would like to add a feature that allows displaying **two results** in the results section: one for the **price estimate** and another for the **time estimate**.

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 10, 2025, 12:18pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/3 "2025-09-10T12:18:39Z")

</div>

Greetings, @Harry_Vonavi 👋

I see that currently both results (price and time) are displayed in the Results section:

 ![image](https://us1.discourse-cdn.com/flex020/uploads/elfsight/original/3X/8/3/836bbff02bfb6591533eeeff61f5b333d3c5c275.png)

Does it look the way you need, or maybe you wanted to display both results in 1 line?

---

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 10, 2025, 2:08pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/4 "2025-09-10T14:08:39Z")

</div>

I didn’t find calculator where I can add time field in normal format like minutes and hours without dot between numbers and it’s pretty complicated to find right formula to get even this result that I have right now.

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 10, 2025, 3:07pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/5 "2025-09-10T15:07:00Z")

</div>

Thanks for clarification!

I completely understand your point and agree that the built-in time calculation feature would make things much simpler.

I’ve moved your idea back to the Wishlist. If more users support this idea, it might be considered in the future.

In the meantime, our devs confirmed that it’s possible to add hours/minutes captions right after the numbers with a custom code.

Your request is in the hands of our devs now. I’ll update you once the solution is ready 🙂

---

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 10, 2025, 3:56pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/6 "2025-09-10T15:56:31Z")

</div>

Thanks

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 11, 2025, 2:29pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/7 "2025-09-11T14:29:01Z")

</div>

Thank you for waiting!

To add the “hours” caption, please add this script to the Custom JS field on the Settings tab of your widget’s settings:

```auto
(() => {
  const RESULT_SELECTOR = '[class*="result-primary__Value-sc"]';
  const ANIMATED_NUMBER_SELECTOR = '[class*="animated-number__Content-sc"]';
  const transformText = (text) => (text ? text.replace(/\./g, ' hours ') : text);

  function createOverlay(targetElement) {
    const parentElement = targetElement.parentElement;
    if (!parentElement) return null;

    const parentStyles = window.getComputedStyle(parentElement);
    if (parentStyles.position === 'static') parentElement.style.position = 'relative';

    const overlayElement = document.createElement('span');
    overlayElement.className = 'user-overlay-numeric';
    overlayElement.style.position = 'absolute';
    overlayElement.style.inset = '0';
    overlayElement.style.display = 'inline-flex';
    overlayElement.style.alignItems = 'center';
    overlayElement.style.justifyContent = 'left';
    overlayElement.style.pointerEvents = 'none';
    overlayElement.style.whiteSpace = 'nowrap';
    overlayElement.style.overflow = 'hidden';
    overlayElement.style.textOverflow = 'ellipsis';
    overlayElement.style.zIndex = '2147483647';

    const targetStyles = window.getComputedStyle(targetElement);
    ['font', 'fontSize', 'fontFamily', 'fontWeight', 'lineHeight', 'letterSpacing', 'textAlign', 'padding', 'margin', 'boxSizing'].forEach(key => {
      overlayElement.style[key] = targetStyles[key];
    });
    overlayElement.style.color = targetStyles.color;
    overlayElement.style.backgroundColor = targetStyles.backgroundColor !== 'rgba(0, 0, 0, 0)' ? targetStyles.backgroundColor : '';

    parentElement.appendChild(overlayElement);
    targetElement.style.visibility = 'hidden';

    return overlayElement;
  }

  function observeAnimatedElement(animatedElement) {
    if (!animatedElement) return;
    const overlay = createOverlay(animatedElement);
    if (!overlay) return;

    const observer = new MutationObserver(() => {
      const updatedText = transformText(animatedElement.textContent || '');
      overlay.textContent = updatedText;
    });

    observer.observe(animatedElement, {
      childList: true,
      subtree: true,
      characterData: true
    });
  }

  const waitForElement = (selector, root = document) =>
    new Promise(resolve => {
      const found = root.querySelector(selector);
      if (found) return resolve(found);
      const observer = new MutationObserver(() => {
        const element = root.querySelector(selector);
        if (element) {
          resolve(element);
          observer.disconnect();
        }
      });
      observer.observe(root, {
        childList: true,
        subtree: true
      });
    });

  waitForElement(RESULT_SELECTOR).then(() => {
    const resultElements = Array.from(document.querySelectorAll(RESULT_SELECTOR));
    const resultElement = resultElements[1];
    if (!resultElement) return console.warn('result not found');
    const animatedNumberElement = resultElement.querySelector(ANIMATED_NUMBER_SELECTOR) || resultElement;
    observeAnimatedElement(animatedNumberElement);
  });
})();

```

  

Custom JS scripts don’t function in the preview mode. So, you’ll be able to see it in action only on your website or through the [Share Link](https://help.elfsight.com/article/1471-how-to-share-widget-via-link)

To add a “minutes” caption, just open the Format setting in your calculations and paste “minutes” into the Suffix field:

 ![image](https://us1.discourse-cdn.com/flex020/uploads/elfsight/original/3X/0/4/04a9af9e4ed4db49fb5d49d44223888afd4ddc32.png) ![image](https://us1.discourse-cdn.com/flex020/uploads/elfsight/original/3X/b/f/bf1d14b37ffa2355a45814307ba75cb618e7d37b.png)

  

Please try it out and let me know if you like the result 🙂

---

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 11, 2025, 2:47pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/8 "2025-09-11T14:47:38Z")

</div>

it looks great, but only for regular type of cleaning. how I can apply js code to each type of cleaning?

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 11, 2025, 2:59pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/9 "2025-09-11T14:59:33Z")

</div>

Ah, sorry about that!

Our devs will review the code, and I’ll update you once it’s done 🙂

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 11, 2025, 3:13pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/10 "2025-09-11T15:13:06Z")

</div>

We’ve slightly adjusted the script in your widget:

```auto
(() => {
  const RESULT_SELECTOR = '[class*="result-primary__Value-sc"]';
  const ANIMATED_NUMBER_SELECTOR = '[class*="animated-number__Content-sc"]';
  const transformText = (text) =>
    text ? text.replace(/\./g, " hours ") : text;

  function createOverlay(targetElement) {
    const parentElement = targetElement.parentElement;
    if (!parentElement) return null;

    const parentStyles = window.getComputedStyle(parentElement);
    if (parentStyles.position === "static")
      parentElement.style.position = "relative";

    const overlayElement = document.createElement("span");
    overlayElement.className = "user-overlay-numeric";
    overlayElement.style.position = "absolute";
    overlayElement.style.inset = "0";
    overlayElement.style.display = "inline-flex";
    overlayElement.style.alignItems = "center";
    overlayElement.style.justifyContent = "left";
    overlayElement.style.pointerEvents = "none";
    overlayElement.style.whiteSpace = "nowrap";
    overlayElement.style.overflow = "hidden";
    overlayElement.style.textOverflow = "ellipsis";
    overlayElement.style.zIndex = "2147483647";

    const targetStyles = window.getComputedStyle(targetElement);
    [
      "font",
      "fontSize",
      "fontFamily",
      "fontWeight",
      "lineHeight",
      "letterSpacing",
      "textAlign",
      "padding",
      "margin",
      "boxSizing",
    ].forEach((key) => {
      overlayElement.style[key] = targetStyles[key];
    });
    overlayElement.style.color = targetStyles.color;
    overlayElement.style.backgroundColor =
      targetStyles.backgroundColor !== "rgba(0, 0, 0, 0)" ? targetStyles.backgroundColor : "";

    parentElement.appendChild(overlayElement);
    targetElement.style.visibility = "hidden";

    return overlayElement;
  }

  function observeAnimatedElement(animatedElement) {
    if (!animatedElement) return;
    const overlay = createOverlay(animatedElement);
    if (!overlay) return;

    const observer = new MutationObserver(() => {
      const updatedText = transformText(animatedElement.textContent || "");
      overlay.textContent = updatedText;
    });

    observer.observe(animatedElement, {
      childList: true,
      subtree: true,
      characterData: true,
    });
  }

  const waitForElement = (selector, root = document) =>
    new Promise((res) => {
      const observer = new MutationObserver(() => {
        const element = root.querySelector(selector);
        if (element) {
          res(element);
          observer.disconnect();
        }
      });

      observer.observe(root, { childList: true, subtree: true });
    });

  const waitForResults = () => {
    waitForElement(RESULT_SELECTOR).then(() => {
      const resultElements = Array.from(
        document.querySelectorAll(RESULT_SELECTOR),
      );
      const resultElement = resultElements[1];
      if (!resultElement) return console.warn("result not found");
      const animatedNumberElement =
        resultElement.querySelector(ANIMATED_NUMBER_SELECTOR) || resultElement;
      observeAnimatedElement(animatedNumberElement);
      waitForResults();
    });
  };

  waitForResults();
})();

```

  

Please check it out and let me know if it’s fine now 🙂

---

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 11, 2025, 3:26pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/11 "2025-09-11T15:26:41Z")

</div>

![image.png](https://us1.discourse-cdn.com/flex020/uploads/elfsight/original/3X/6/f/6fe44660250e6b50e55a2cf38185dc90add59371.png)yes, now it works great for each type. Last request - is it possible to make it working for both primary and secondary results? because now it’s working only for primary result only

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 11, 2025, 3:43pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/12 "2025-09-11T15:43:43Z")

</div>

Okay! I’ll let you know once the devs share the final solution 🙂

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 12, 2025, 4:44pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/13 "2025-09-12T16:44:37Z")

</div>

Hi @Harry_Vonavi 👋

We’ve added this code to the Custom JS field:

```auto
const isPrimary = true;
const PRIMARY = 'result-primary__Value-sc';
const SECONDARY = 'result-secondary__Value-sc';
(() => {
  const RESULT_SELECTOR = `[class*="${isPrimary ? PRIMARY : SECONDARY}"]`;
  const ANIMATED_NUMBER_SELECTOR = '[class*="animated-number__Content-sc"]';
  const transformText = (text) =>
    text ? text.replace(/\./g, " hrs ") : text;

  function createOverlay(targetElement) {
    if (!targetElement || targetElement.dataset.overlayCreated) return null; // <-- добавили проверку

    const parentElement = targetElement.parentElement;
    if (!parentElement) return null;

    const parentStyles = window.getComputedStyle(parentElement);
    if (parentStyles.position === "static")
      parentElement.style.position = "relative";

    const overlayElement = document.createElement("span");
    overlayElement.className = "user-overlay-numeric";
    overlayElement.style.position = "absolute";
    overlayElement.style.inset = "0";
    overlayElement.style.display = "inline-flex";
    overlayElement.style.alignItems = "center";
    overlayElement.style.justifyContent = "left";
    overlayElement.style.pointerEvents = "none";
    overlayElement.style.whiteSpace = "nowrap";
    overlayElement.style.overflow = "hidden";
    overlayElement.style.textOverflow = "ellipsis";
    overlayElement.style.zIndex = "2147483647";

    const targetStyles = window.getComputedStyle(targetElement);
    [
      "font",
      "fontSize",
      "fontFamily",
      "fontWeight",
      "lineHeight",
      "letterSpacing",
      "textAlign",
      "padding",
      "margin",
      "boxSizing",
    ].forEach((key) => {
      overlayElement.style[key] = targetStyles[key];
    });
    overlayElement.style.color = targetStyles.color;
    overlayElement.style.backgroundColor =
      targetStyles.backgroundColor !== "rgba(0, 0, 0, 0)" ? targetStyles.backgroundColor : "";

    parentElement.appendChild(overlayElement);
    targetElement.style.visibility = "hidden";

    targetElement.dataset.overlayCreated = "true"; // <-- помечаем

    return overlayElement;
  }

  function observeAnimatedElement(animatedElement) {
    if (!animatedElement) return;
    const overlay = createOverlay(animatedElement);
    if (!overlay) return;

    const observer = new MutationObserver(() => {
      const updatedText = transformText(animatedElement.textContent || "");
      overlay.textContent = updatedText;
    });

    observer.observe(animatedElement, {
      childList: true,
      subtree: true,
      characterData: true,
    });
  }

  const waitForElement = (selector, root = document) =>
    new Promise((res) => {
      const observer = new MutationObserver(() => {
        const element = root.querySelector(selector);
        if (element) {
          res(element);
          observer.disconnect();
        }
      });

      observer.observe(root, {
        childList: true,
        subtree: true
      });
    });

  const waitForResults = () => {
    waitForElement(RESULT_SELECTOR).then(() => {
      const resultElements = Array.from(
        document.querySelectorAll(RESULT_SELECTOR),
      );
      const idx = isPrimary ? 1 : 0;
      const resultElement = resultElements[idx];
      if (!resultElement) return console.warn("result not found");
      const animatedNumberElement =
        resultElement.querySelector(ANIMATED_NUMBER_SELECTOR) || resultElement;

      if (!animatedNumberElement.dataset.overlayCreated) {
        observeAnimatedElement(animatedNumberElement);
      }

      waitForResults();
    });
  };

  waitForResults();
})();

```

  

Please test it out and let me know if you like the result 🙂

---

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 12, 2025, 4:57pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/14 "2025-09-12T16:57:13Z")

</div>

after inserting a new code I see all results with a dot again

 ![image.png](https://us1.discourse-cdn.com/flex020/uploads/elfsight/original/3X/9/7/97f73304460c108a576deb639d7dacfeed77a5da.png)

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 12, 2025, 5:23pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/15 "2025-09-12T17:23:31Z")

</div>

Just to clear things up, at the moment you have only primary results in your widget. Would you like to change all of them to secondary? Or only some of them?

---

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 12, 2025, 6:16pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/16 "2025-09-12T18:16:32Z")

</div>

I’m not decided yet, just want to be sure that I have right JC code, if I decide to change it to secondary option

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 12, 2025, 6:26pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/17 "2025-09-12T18:26:21Z")

</div>

Got it!

If you decide to make all results secondary, this code should work for you 🙂

```auto
const isPrimary = false;
const PRIMARY = 'result-primary__Value-sc';
const SECONDARY = 'result-secondary__Value-sc';
(() => {
  const RESULT_SELECTOR = `[class*="${isPrimary ? PRIMARY : SECONDARY}"]`;
  const ANIMATED_NUMBER_SELECTOR = '[class*="animated-number__Content-sc"]';
  const transformText = (text) =>
    text ? text.replace(/\./g, " hrs ") : text;

  function createOverlay(targetElement) {
    if (!targetElement || targetElement.dataset.overlayCreated) return null; // <-- добавили проверку

    const parentElement = targetElement.parentElement;
    if (!parentElement) return null;

    const parentStyles = window.getComputedStyle(parentElement);
    if (parentStyles.position === "static")
      parentElement.style.position = "relative";

    const overlayElement = document.createElement("span");
    overlayElement.className = "user-overlay-numeric";
    overlayElement.style.position = "absolute";
    overlayElement.style.inset = "0";
    overlayElement.style.display = "inline-flex";
    overlayElement.style.alignItems = "center";
    overlayElement.style.justifyContent = "left";
    overlayElement.style.pointerEvents = "none";
    overlayElement.style.whiteSpace = "nowrap";
    overlayElement.style.overflow = "hidden";
    overlayElement.style.textOverflow = "ellipsis";
    overlayElement.style.zIndex = "2147483647";

    const targetStyles = window.getComputedStyle(targetElement);
    [
      "font",
      "fontSize",
      "fontFamily",
      "fontWeight",
      "lineHeight",
      "letterSpacing",
      "textAlign",
      "padding",
      "margin",
      "boxSizing",
    ].forEach((key) => {
      overlayElement.style[key] = targetStyles[key];
    });
    overlayElement.style.color = targetStyles.color;
    overlayElement.style.backgroundColor =
      targetStyles.backgroundColor !== "rgba(0, 0, 0, 0)" ? targetStyles.backgroundColor : "";

    parentElement.appendChild(overlayElement);
    targetElement.style.visibility = "hidden";

    targetElement.dataset.overlayCreated = "true"; // <-- помечаем

    return overlayElement;
  }

  function observeAnimatedElement(animatedElement) {
    if (!animatedElement) return;
    const overlay = createOverlay(animatedElement);
    if (!overlay) return;

    const observer = new MutationObserver(() => {
      const updatedText = transformText(animatedElement.textContent || "");
      overlay.textContent = updatedText;
    });

    observer.observe(animatedElement, {
      childList: true,
      subtree: true,
      characterData: true,
    });
  }

  const waitForElement = (selector, root = document) =>
    new Promise((res) => {
      const observer = new MutationObserver(() => {
        const element = root.querySelector(selector);
        if (element) {
          res(element);
          observer.disconnect();
        }
      });

      observer.observe(root, {
        childList: true,
        subtree: true
      });
    });

  const waitForResults = () => {
    waitForElement(RESULT_SELECTOR).then(() => {
      const resultElements = Array.from(
        document.querySelectorAll(RESULT_SELECTOR),
      );
      const idx = isPrimary ? 1 : 0;
      const resultElement = resultElements[idx];
      if (!resultElement) return console.warn("result not found");
      const animatedNumberElement =
        resultElement.querySelector(ANIMATED_NUMBER_SELECTOR) || resultElement;

      if (!animatedNumberElement.dataset.overlayCreated) {
        observeAnimatedElement(animatedNumberElement);
      }

      waitForResults();
    });
  };

  waitForResults();
})();

```

---

<div class="post-metadata">

**Author:** ![Harry\_Vonavi](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/harry_vonavi/32/76173_2.png) [@Harry\_Vonavi](https://community.elfsight.com/u/Harry_Vonavi)\
**Post date:** [September 12, 2025, 6:36pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/18 "2025-09-12T18:36:40Z")

</div>

oh, so two different JC codes for two different settings  
ok, got it, thanks for your help!

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 12, 2025, 6:37pm UTC](https://community.elfsight.com/t/time-calculation-feature/139487/19 "2025-09-12T18:37:57Z")

</div>

It’s my pleasure 😉

---

<div class="post-metadata">

**Author:** ![Max](https://sea2.discourse-cdn.com/flex020/user_avatar/community.elfsight.com/max/32/710_2.png) [@Max](https://community.elfsight.com/u/Max)\
**Post date:** [September 15, 2025, 11:34am UTC](https://community.elfsight.com/t/time-calculation-feature/139487/20 "2025-09-15T11:34:13Z")

</div>

Split this topic on September 15, 2025, 11:34am UTC

2 posts were split to a new topic: [Sync results on different pages](https://community.elfsight.com/t/sync-results-on-different-pages/139652)
