I put the following in a CEWP script editor on a list page. Works fine the first time I hit save page. When I close browser or navigate away from page then return it never works again. MDS is disabled for this site collection. It's as if the script never gets loaded or run after the first time I enter it in the CEWP and hit save. I repeated this and if I go back into edit page and then hit save, again it will work until I navigate away. I am not a coder so this is becoming a multi-day search for a solution. I have a list that has several views with many rows that users must use quick edit daily. Freezing the header row is imperative. Thanks to anyone willing to help direct me to a solution! #pullingmyhairout

` /* Sticky headers for all Custom Lists, Document Libraries and administration lists * --------------------------------------------- * Created by Daniel Stoelzner * [email protected] * http://spoodoo.com * Copyright (c) 2017 Daniel Stoelzner (Licensed under the MIT X11 License) * v3.2.0 for SharePoint 2013 and SharePoint Online * LastMod: 19th of July, 2017 * --------------------------------------------- * Dependencies: jQuery - http://jquery.com * --------------------------------------------- * Add a reference to this file in a CEWP or Script Editor Web Part or reference this file in your masterpage */

/* * - Fixed a bug where Sticke Headers are not working in Datasheet-view when the user has less than Edit-permission * - Implemented a funtion that will load jQuery for you if it is not already loaded. No need to load jQuery via a separate script-tag any longer. NOTE: Uncomment line 23-29 and remove or comment out line 32-50 if you don't want this feature * - Added some semicolons for a better minification */

/* jQuery(function () { if(typeof asyncDeltaManager != "undefined"){ asyncDeltaManager.add_endRequest(stickyHeaders); } else { stickyHeaders(); } }); */

if (typeof asyncDeltaManager != "undefined"){ asyncDeltaManager.add_endRequest(loadJQueryFirstOrExecuteDirectly); } else { loadJQueryFirstOrExecuteDirectly(); };

function loadJQueryFirstOrExecuteDirectly(){ if(window.jQuery === undefined) { var script = document.createElement("script"); script.type = "text/javascript"; script.onload = function(){ stickyHeaders(); }; (document.getElementsByTagName("head")[0]).appendChild(script); script.src = "//code.jquery.com/jquery-3.2.1.min.js"; } else { stickyHeaders(); }; }

function stickyHeaders() { window.SHListContainer = []; function findListsAndAttachHandlers() { jQuery("tr:has(>th[class*=ms-vh]):visible").closest("table").each(function(){ var list = new List(jQuery(this)); window.SHListContainer.push(list); list.init(); list.webpart.data("stickyHeaderData",list); jQuery("#s4-workspace").on("scroll.stickyHeaders", {elem: list}, function (event) { event.data.elem.update(); }); jQuery(window).on("resize.stickyHeaders", {elem: list}, function (event) { setTimeout(function(){ event.data.elem.setWidth(); event.data.elem.update(); },50); }); if(list.fixedHeight || list.fixedWidth){ list.webpart.on("scroll.stickyHeaders", {elem: list}, function(event){ event.data.elem.update(); }); }; if(typeof ReRenderListView == "function") { var ReRenderListView_old = ReRenderListView; ReRenderListView = function(b, l, e){ ReRenderListView_old(b, l, e); jQuery("#WebPart" + b.wpq).data("stickyHeaderData").init(); }; } }); var ribbonHeight = 0; g_workspaceResizedHandlers.push(function () { var newRibbonHeight = jQuery("#RibbonContainer").height(); if(ribbonHeight !== newRibbonHeight) { jQuery(window.SHListContainer).each(function(){ this.s4OffsetTop = jQuery("#s4-workspace").offset().top; this.update(); }); ribbonHeight = newRibbonHeight; } });

    var ExpCollGroup_old = ExpCollGroup;
    ExpCollGroup = function (c, F, y, w) {
        ExpCollGroup_old(c, F, y, w);
        var element = ("#tbod" + c + "_, #titl" + c);
        var interval = setInterval(function () {
            if(jQuery(element).attr("isloaded") == "true" || typeof jQuery(element).attr("isloaded") == "undefined") {
        }, 100);

function List(list) {
    this.list           = list;
    this.webpart        = jQuery(this.list.closest("div[id^=WebPartWPQ]")[0] || this.list[0]);
    this.fixedHeight    = ["","auto","100%"].indexOf(this.webpart.prop("style")["height"]) + 1 ? false : true;
    this.fixedWidth     = ["","auto","100%"].indexOf(this.webpart.prop("style")["width"])  + 1 ? false : true;
    this.init = function() {
        this.s4OffsetTop    = jQuery("#s4-workspace").offset().top;
        this.list           = jQuery.contains(document.documentElement, this.list[0]) ? jQuery(this.list) : jQuery(this.webpart.find(".ms-listviewtable").last()[0] || this.webpart.find("> table")[0]);
        this.listType       = this.list.find("tbody[id^=GroupByCol]").length ? "GroupedList" : this.list.hasClass("ms-listviewgrid") ? "Grid" : typeof this.list.closest("div[id^=WebPartWPQ]")[0] == "undefined" ? "SysList" : "NormalList";
        this.firstRow       = this.list.find("thead").length ? (this.listType == "GroupedList" ? this.list.find("tbody[isloaded=true]:visible > tr").first() : this.list.find("> tbody > tr:nth-child(1)")) : this.list.find("> tr:nth-child(2), > tbody > tr:nth-child(2)");
        this.prevHeight     = this.listType == "Grid" ? this.list.parent().closest(".ms-listviewtable")[0].offsetTop : this.list[0].offsetTop; //little bug in Edge: value wrong after pagination
        this.sticky         = this.webpart.find("tr:has(>th[class*=ms-vh]):visible").first();
        this.stickyHeight   = this.sticky.outerHeight();
        this.webpartHeight  = this.webpart.height();
        if(this.listType == "Grid") {
                "table-layout": "fixed",
                "width"       : "auto"
            jQuery("#spgridcontainer_" + this.webpart.attr("id").substr(7))[0].jsgrid.AttachEvent(SP.JsGrid.EventType.OnCellEditCompleted, (function(caller){
                return function(){
                    caller.setWidth.apply(caller, arguments);
            this.sticky.find("a").on("click", this.fixSortFunctionality);
                if(jQuery(e.target).parents(".stickyHeader").length > 0){
                    jQuery(e.target).find(".clip9x6").css("visibility", e.type == "mouseenter" ? "visible" : "hidden").find("> img").show();
            }).on("mouseleave", function(e){
                if(jQuery(e.target).parents(".stickyHeader").length > 0){
                    jQuery(e.target).find(".clip9x6").css("visibility", "hidden").find("> img").show();
        if(this.sticky.find("th:last-child.ms-vh-icon:has(>span.ms-addcolumn-span)").hide().length) {
    this.fixSortFunctionality = function(e){
        if(jQuery(e.target).parents(".stickyHeader").length > 0){
            var clvp = jQuery(e.target).closest(".ms-listviewtable:not(.ms-listviewgrid)")[0].clvp;
            var strHash = ajaxNavigate.getParam("InplviewHash" + clvp.wpid);
            var result = {};
            strHash.split("-").forEach(function(part) {
                var item = part.split("=");
                result[item[0]] = decodeURIComponent(item[1]);
            var prevSortField = result.SortField;
            result.SortField = jQuery(e.target).closest("th")[0].thColumnKey;
            result.SortDir = prevSortField != result.SortField ? "Asc" : result.SortDir == "Asc" ? "Desc" : "Asc";
            var params = $.param(result);
            InitGridFromView(clvp.ctx.view, true);
            clvp.strHash = params.replace(/&/g, "-");
            clvp.fRestore = true;
            clvp.RefreshPagingEx("?" + params, true, null);
    this.setWidth = throttleUpdates(function() {
            "position": "static",
            "display" : "table-row"
        var stickyChildren   = this.sticky.children("th");
        var firstRowChildren = this.firstRow.children("td");
        jQuery.each([stickyChildren, firstRowChildren], function(){
            jQuery(this).css("min-width", 0);
        var stickyChildrenWidths = [], firstRowChildrenWidths = [];
        for(var i=0; i < stickyChildren.length; i++){
        for(var i=0; i < stickyChildren.length; i++){
            jQuery(stickyChildren[i]).css("min-width",   stickyChildrenWidths[i]);
            jQuery(firstRowChildren[i]).css("min-width", firstRowChildrenWidths[i]);
        this.sticky.css("position", this.sticky.hasClass("stickyHeader") ? "fixed" : "static")
    this.update = throttleUpdates(function() {
        if(this.fixedWidth) {
        this.webpartOffsetTop = this.webpart.offset().top;
        if(this.firstRow.length && (this.webpartOffsetTop + this.webpartHeight - this.s4OffsetTop > 0 && (this.webpartOffsetTop - this.s4OffsetTop + this.prevHeight < 0 || this.webpart.scrollTop() > this.prevHeight))){
            if(!this.sticky.hasClass("stickyHeader")) {
                "left": this.webpart.offset().left,
                "top" : (!this.fixedHeight || this.webpartOffsetTop < (this.s4OffsetTop + 2)) ? (this.s4OffsetTop + 2) : (this.webpartOffsetTop)
        } else {
            if(this.sticky.hasClass("stickyHeader")) {
    this.toggleSticky = function(mode){
        if(this.listType == "SysList"){
            var headerChildren = (this.listType == "GroupedList") ? this.list.find("tbody[id^=titl]").first().find("td") : this.firstRow.children("td");
            var _stickyHeight = this.stickyHeight;
                jQuery(this).css("padding-top", parseInt(jQuery(this).css("padding-top")) + _stickyHeight * (mode == true ? 1 : -1));
        } else {
            mode ? this.list.css("padding-top", this.stickyHeight) : this.list.css("padding-top", 0);
            "position": mode ? "fixed" : "static",
            "display" : mode ? "none"  : "table-row"
        mode ? this.sticky.addClass("stickyHeader").slideDown(200) : this.sticky.removeClass("stickyHeader");
 * Throttle function extracted from:
 * http://benalman.com/projects/jquery-throttle-debounce-plugin/
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
function throttleUpdates(t,e){function u(){function e(){n=+new Date,t.apply(u,d)}var u=this,a=+new Date-n,d=arguments;i&&clearTimeout(i),a>r?e():i=setTimeout(e,r-a)}var i,n=0,r=50;return jQuery.guid&&(u.guid=t.guid=t.guid||jQuery.guid++),u}
(function () {
    if(!jQuery("#MSOLayout_InDesignMode").val() && !jQuery("#_wikiPageMode").val()){
        if(jQuery.inArray("spgantt.js", g_spPreFetchKeys) > -1) {
            ExecuteOrDelayUntilScriptLoaded(function () {
                setTimeout(function () {
                }, 0)
            }, "spgantt.js")
        } else {
        if(typeof _spWebPartComponents != "undefined" && Object.keys(_spWebPartComponents).length == 1) {
                var ShowContextRibbonSections = (function fn(){
                    SP.Ribbon.WebPartComponent.registerWithPageManager({editable: true, isEditMode: false, allowWebPartAdder: false});
                    SP.Ribbon.WebPartComponent.get_instance().selectWebPart(jQuery("#MSOZoneCell_" + Object.keys(_spWebPartComponents))[0], true);
                    return fn
                    var DeselectAllWPItems_old = DeselectAllWPItems;
                    DeselectAllWPItems = function () {
                        setTimeout(function () { 
                        }, 25)
                }, "core.js")
            }, "sp.ribbon.js")
        var style = ".stickyHeader {" +
                        "border: 1px solid grey;" +
                        "background-color: white;" +
                        "box-shadow: 0 0 6px -2px black;" +
                        "z-index: 1;" +
                    "}" +
                    ".stickyHeader > th {" +
                        "position: relative;" +
                    "}" +
                    ".ms-listviewtable th .ms-core-menu-box {" +
                        "top: auto !important;" +
                        "left: auto !important;" +
                    "}" +
                    ".stickyHeader th:not([id^=spgridcontainer]) {" +
                        "border-bottom: 0 !important;" +
                    "}" +
                    ".ms-listviewtable.addPadding {" +
                        "padding-right: 26px !important;" +
        var div = jQuery("<div />", {
            html: "&shy;<style>" + style + "</style>"

} `

  • You say "CEWP script editor", but do you mean a Content Editor web part or a Script Editor web part? Are you pasting all that code directly into the web part? Apr 8, 2020 at 18:52
  • I meant script editor web part, this is the only way I can get it to work. it works once but when I leave that view it does not upon refresh or return. I tried using a CEWP instead and referencing URL to js in the edit web part like I have done for other scripting but that did not work at all. Thanks for your help Apr 8, 2020 at 20:04

1 Answer 1


I'm guessing that you are trying to paste all that code directly into either a Script Editor web part or a Content Editor Web Part (CEWP). Those are two different things.

But in any case, if you look near the top of that code, you see (emphasis mine):

Add a reference to this file in a CEWP or Script Editor Web Part

Adding a reference to the sticky headers javascript file does not mean copy and paste that code into a Script Editor web part. The word "reference" implies loading that code in a different way.

So here's what you should do:

  1. Upload the stickyHeaders_3.2.0.js file into the Site Assets library on the site where you want to use it. Personally, I like to create a "js" folder in the Site Assets library to keep all the script files I use organized and separate from all the other stuff that might get uploaded into the Site Assets library, bu that's just me.
  2. Go to the list where you want the sticky headers, edit the page, and at the top (above the list view), add a Script Editor Web Part (not a Content editor, remember they are different things).
  3. Click "edit snippet" to add some script.
  4. Add the following little bit of script to the script editor:

<script type="text/javascript" src="/sites/YourSiteName/SiteAssets/stickyHeaders_3.2.0.js"></script>

  1. That source path will vary, depending on whether or not you put the script file in a folder. Since I like to put mine in a "js" folder, mine would look like: /sites/MySiteName/SiteAssets/js/stickyHeaders_3.2.0.js
  2. Close the script editor and save the page.

That should effectively "reference" the sticky headers code file without pasting all that code directly into a web part on your list view page.

Now, keep in mind that because SharePoint treats all views as though they were separate pages (AllItems.aspx, SomeOtherViewName.aspx), web parts that are added to those pages are not automatically added to the other view pages. So you will have to go to every view where you want the sticky headers, and follow the same process of adding a Script Editor and adding the reference to the sticky headers file.

In your comment you mention that you have used a Content Editor and referenced the URL to a js file on other occasions to link in scripts. If that's the case, you might want to try that again - I actually prefer doing that than using the Script Editor.

However, the reason it's probably not working for you in this instance is that the stickyHeaders_3.2.0.js file is a true, pure Javascript file, whereas other "scripts" you have linked to in the past, even if they have the file extension .js, probably have a little HTML in them.

This is because what the CEWP does, when you use the "content link" to pull in a file, is just dump the contents of that file as-is into the HTML of the page. If you dump just pure Javascript into HTML, the browser is not going to know it's Javascript, and it's going to either ignore it or actually render the code out as content so you will see the code as text right on the web page.

Any "script" files that you link in using a CEWP, again, even if they have a file extension of .js, probably start and end with HTML <script> tags:

<script type="text/javascript">  <!-- this is actually an HTML element -->

    // all the actual script is in here,
    // which the browser can now interpret
    // as actual code, because it's wrapped
    // in HTML <script> tags


Now, one thing you could try would be to edit the stickyHeaders_3.2.0.js file and add <script type="text/javascript"> as the first line and </script> as the last line, and then link to that file through a CEWP. But to me, that just confuses things because you have HTML in a .js file.

I would keep sickyHeaders_3.2.0.js as it is, and create a new file, lets say you call it stickyHeaders-link.html, and in that HTML file just have the one line:

<script type="text/javascript" src="/sites/YourSiteName/SiteAssets/stickyHeaders_3.2.0.js"></script>

Then upload that one-line HTML file to your Site Assets, and then in the CEWP, in the content link, use the URL to the HTML file:


That way everything stays clear and organized: Javascript (and only Javascript) is in a .js file, HTML is in a .html file, and the CEWP is dumping HTML into the middle of the HTML of the page.

  • Thank you, yes I meant I had placed the code in a script editor web part. I also tried using a CEWP and referencing URL (as I have done this with other code in the past). I could only get it to work once when I used the script editor web part. I just tried your suggestion. Put the script with the "text/javascript" src=... in a content editor web part as you had called out in your answer but it did not work. I have the js file in the site assets folder. Apr 8, 2020 at 20:00
  • So I went back to several views of this list and placed a script editor web part with the code wrapped in script tags like I had done before. Now it seems to work. I wonder why it is so intermittent. Is it bad practice to use a script editor and paste code directly in? Apr 8, 2020 at 20:17
  • Not necessarily. A SEWP is meant to do just that, add some script to a page. At first I was thinking it might be the amount of script - all that code for the sticky headers is a lot, and I don't know if there is a length limit for a SEWP. I actually don't like working with SEWPs to add script, I usually only use them to add tiny bits of CSS to a page if I need to, because SEWPs also allow <style> tags. For linking in javascript, I much prefer the method I talked about in the updated part of my answer: use a CEWP to link to an .html file, where the .html file has the....(cont'd) Apr 8, 2020 at 20:36
  • ... <script> tags that actually point to other .js files in the Site Assets library. I've found doing it that way to be quite reliable. If you need to change the Javascript code, you just edit that file and upload the new one to Site Assets, no need to go to the page where it is and edit the page. If you want to add more Javascript, or some CSS, you can upload them to Site Assets and just edit the .html file to add more <script> or a <link> tag. You never have to go back and edit the content link in the CEWP. Apr 8, 2020 at 20:40
  • @Midwestsusan updated my answer and addressed your comments. Apr 8, 2020 at 20:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.