Elementor smooth scroll to Anchor

Uses Plugins

Elementor PRO


Smooth scrolling to Anchors in Elementor is normally done using Menu Anchor Widgets.

I find a couple of issues with this.

  1. The window scrolls the top of the anchor to the top of the window. This does not allow for any fixed headers etc.
  2. Sometimes you can’t use a Menu Anchor Widget. E.g. if you are using a JetEngine repeater and want to scroll to sections

This video shows a way that you can do a smooth scroll to any anchor and specify the top offset.



The code we will add will target <a href="#target-id"> tags with the class "scroll-to" and the data attribute 'data-top-offset="xxx"'

This will smooth scroll the target element with "target-id" and place it "xxx" pixels from the top of the window.

In this example, we will use 2 x JetEngine Repeaters based on the same  Post Meta.

The first Repeater will be T.O.C with links to the "Steps"

E.g. the first T.O.C item will have a link <a href="#step_1" data-top-offset="150">Step 1 Title</a>

The second Repeater will have the Step Title and Step Contents. The Title will have the id="step_1".

E.g. <h3 id="step_1">Add an HTML Widget to the Editor</h3>


Custom Code


  1. Go to Elementor -> Custom Code
  2. Click "Add New"
  3. Give it a name
  4. Copy and paste the JS code below.
  5. Set the display conditions to the entire site.

Note:  The code formatted strips the <script> tags. You will need to wrap the code in <script></script> tags.

Code (click to copy)

JavaScript (javascript)

JavaScript code. Paste into a new Elementor Custom Code for site-wide usage.

To use on an HTML Widget, paste inside <script></script> tags.

;(w => {
    let $, $scrollToTriggers;
    w.addEventListener('DOMContentLoaded', () => {
        $ = jQuery;

    const init = () => {
        console.info('INIT - Scroll To Smooth with offset');
        $scrollToTriggers = $(".scroll-to");
        $scrollToTriggers.on('click', (e) => {
            const {currentTarget} = e;
            const $currentTarget = $(currentTarget);
            const hash = currentTarget.hash;
            const target = $(hash)[0];
            const offset = $currentTarget.data('top-offset');
            const pos = target.getBoundingClientRect().top + window.scrollY - offset;
                top: pos,
                behavior: "smooth"