Elementor: two ways to add an offset to the Table of Contents widget when scrolling – tutorial with code

Table of Contents is a relatively new Elementor Pro widget that is very useful and works well. However, it does not have a built-in option to define an offset when scrolling content. Here are two different and independent ways to overcome this shortcoming. Both solutions involve the use of custom code, which is included for both.


I recently worked as a subcontractor on a project for a designer client, which involved creating an Elementor single-post template. The Figma design I used to create the site required a Content table, which is best achieved in Elementor by using its native Table of Contents widget.

Table of Contents Elementor widget

The site I was working on has a sticky header, and that’s where the problem arose. Elementor’s Table of Contents widget doesn’t have a built-in option to adjust the offset for scrolling to a target anchor. In this case, when a site visitor clicked on a link in the content, the heading was positioned at the top (the posts on the site are quite long, so they can’t fit on one page) and was underlined below the header. The target title was then not visible, only the content below it – and that wasn’t a good user experience.

You can see how it looks by default here:

Table of Contest wifhout offset
Table of Contents scrolling behavior without adding custom code

 

Elementor (i.e., its TOC widget) does not have a built-in solution for this problem, so it must be sought through the use of additional custom code. Through research and experimentation, I came up with two different and good solutions to this problem, and I will present both of them here.

Both solutions also involve setting different offsets for different screen sizes; I set them according to the common screen width values ​​for desktop, tablet, and mobile screens (I set the offset values ​​to 60px, 55px, and 50px, respectively). Of course, all of this is easily customizable if your needs are different.

Both solutions presented apply exclusively to the Pro version of Elementor.

A simpler solution: using CSS

The first solution is surprisingly simple to implement, and the code is easy to understand. It relies entirely on CSS. The code is entered into the Custom CSS section of the Table of Contents widget. For the values ​​I announced above, the code entered into the Advanced > Custom CSS field of this widget looks like this:


:root {
    scroll-padding-top: 60px;
}

@media (max-width: 1024px) {
    :root {
        scroll-padding-top: 55px;
    }
}

@media (max-width: 767px) {
    :root {
        scroll-padding-top: 50px;
    }
}

I know you know this, but I’ll mention it anyway: don’t use the selector keyword in this case.

The advantage of this solution is, obviously, its simplicity and ease of use. This solution is perfect if you don’t need any additional degree of control or effect (e.g., smooth scrolling).

You can see how it all looks after applying this (CSS) solution here:

Table oc Contents Elementor widget with offset
Table of Contents scrolling behavior after using the CSS solution

 

More complex solution: using JS

Another solution uses custom JS code. This code is entered from the WP dashboard, not from the Elementor editor. Go to WP dashboard > Elementor > Custom Code. Create a new code snippet and give it a name of your choice, execution location body-end, priority 1. The complete code is this:

<script>
/* jshint esversion: 6 */
document.addEventListener('DOMContentLoaded', function () {
let offsetDesktop = 60;
let offsetTablet = 55;
let offsetMobile = 50;

function getOffset() {
if (window.innerWidth <= 768) return offsetMobile;
  if (window.innerWidth <= 1024) return offsetTablet;
  return offsetDesktop;
}

function smoothScroll(targetId) {
let targetElement = document.getElementById(targetId);
if (targetElement) {
  let elementPosition = targetElement.getBoundingClientRect().top + window.scrollY;
  window.scrollTo({
  top: elementPosition - getOffset(),
  behavior: 'smooth'
});
}
}

function overrideTOCScroll() {
  document.querySelectorAll('.elementor-widget-table-of-contents a[href^="#"]').forEach(anchor => {
    anchor.addEventListener('click', function (e) {
    e.preventDefault();
    let targetId = this.getAttribute('href').substring(1);
    smoothScroll(targetId);
    });
  });
}

overrideTOCScroll();

let observer = new MutationObserver(() => overrideTOCScroll());
  observer.observe(document.body, { childList: true, subtree: true });
});
</script>

The advantage of this solution is a greater degree of control. In the above code, smooth scrolling is introduced. In all other respects, the result is the same as in the first solution. This solution is recommended if beautiful effects are a higher priority for you than simplicity.

Table of Contents is a relatively new Elementor Pro widget that is very useful and works well. However, it does not have a built-in option to define an offset when scrolling content. Here are two different and independent ways to overcome this shortcoming.

About the author

Obren Markov, Senior WordPress Developer and Elementor Expert

Obren Markov is a WordPress developer and designer with many years of experience in this field and several dozen created websites behind him. He is an Elementor Professional and the author of Template sets, who creates sites for end-users. Also works with agencies and independent WP designers as a subcontractor on their projects.

Basically about me

I’m Obren Markov, a senior WordPress developer, a qualified and university-educated IT professional accepted in Envato/ThemeForest as an Elementor template author and also in the Elementor Expert community.

I work directly for end users, but also for agencies and independent designers, complementing them in their projects.