Bring Drag & Drop to Dash with Dashboard Engine. 💫 Learn how at our next webinar!

Custom local JavaScript scroll events?

I’m working on a Dash app native in python and trying to add custom javascript locally, but having trouble figuring out how to get it to load. I’m a bit of a novice here, but couldn’t find anyone addressing this anywhere.

Specifically, I’m looking to add a standard function to add a .sticky class to my page header on a scroll event (specifically to add a drop shadow after scrolling).

I’ve read the documentation, which led me to understand that loading local javascript files was as simple as adding .js files with your desired script to the “assets/” folder. I’ve followed this protocol with CSS files successfully.

To that end, I’ve add a file “base-javascript.js” to my assets folder with the following script:

window.onscroll = function() {stickyHeaderStyling()};

var header = document.getElementById("app-page-header");
var sticky = header.offsetTop;

function stickyHeaderStyling() {
  if (window.pageYOffset > sticky) {
    header.classList.add("sticky");
  } else {
    header.classList.remove("sticky");
  }
}

I separately have the following in a .css file within the same location:

#app-page-header {
    width: 100% !important;
    height: 60px !important;
    position: fixed !important;
    top: 0px;
    left: 0px;
    z-index: 1;
}

#app-page-header.sticky {
    border-bottom: .0625rem solid #f4f3f3;
    box-shadow: 0 0.375rem 0.9375rem 0 rgba(26,22,40,.1);
}

All of my other styling is working, but I’m not able to get the .sticky class to be applied as intended on scroll events. My guess is that I need to include a callback to trigger my javascript function or something, but am a bit lost here.

Any help would be greatly appreciated!

Bumping here - anyone able to help point me in the right direction? I’ve searched everywhere but can’t find anything that works.

The issue is that when the javascript is executed, your app-page-header element has not been injected in the DOM yet. I usually work around this by putting said code in a clientside callback as follows:

app.py

from dash.dependencies import Input, Output, State, ClientsideFunction

# ...

app.clientside_callback(
    ClientsideFunction("clientside", "stickyHeader"),
    Output("app-page-header", "data-loaded"),  # Just put some dummy output here
    [Input("app-page-header", "id")],  # This will trigger the callback when the object is injected in the DOM
)

assets/scripts.js

if(!window.dash_clientside) {window.dash_clientside = {};}

window.dash_clientside.clientside = {

  stickyHeader: function(id) {
    var header = document.getElementById("app-page-header");
    var sticky = header.offsetTop;
    
    window.onscroll = function() {
      if (window.pageYOffset > sticky) {
        header.classList.add("sticky");
      } else {
        header.classList.remove("sticky");
      }
    };

    return window.dash_clientside.no_update
  },
}

That said, I would suggest to be wary of performance with onscroll event listener :slight_smile:

Thanks!

I haven’t quite gotten it working as anticipated yet, but am sure it’s something silly I’m overlooking on my end (it’s a fairly robust web app, so quite a few parts to make sure it’s playing nicely with).