Chidi Okwudire IT Professional. ERP Enthusiast. NetSuite Certified (Administrator, SuiteCloud Developer II, and ERP Consultant). Celigo Certified (Level 4+). Passionate About Empowerment Through Knowledge Sharing. Always Eager to Learn.

A NetSuite Sticky Headers Solution That Works

5 min read

Edet, the NetSuite Admin at Asoville Inc., has always wondered why NetSuite’s table headers are not sticky! Recently, she stumbled upon an article online that got her on track. With help from her colleague, Larry, who is more versed in web technologies, they were able to create a solution that works from within NetSuite. And they’ve decided to share it with you!


TL;DR

NetSuite Sticky Headers Demo
NetSuite Sticky Headers in Action
  • Non-sticky headers in NetSuite make working with long sublists / tables difficult and frustrating.
  • This issue can be tackled in multiple ways, the preferred solution being to inject a client-side script before loading a NetSuite page.
  • The complete solution depicted above including a bonus step-by-step guide on how to deploy it is yours for the asking… simply because you deserve to know.

Problem

You probably know the feeling: You’re working with a transaction with several lines or any other NetSuite table (a.k.a. “sublist”) view and as you scroll, the header row disappears, making it hard for you to figure out which column is which. Such a header is considered non-sticky, floating or not locked (it’s all the same thing).

Several NetSuite sublists also feature a floating action bar that allows you to quickly perform certain actions like duplicate a transaction row. However, when scrolling horizontally in a table view with multiple columns, the action bar disappears as well.

This is pretty standard functionality which you’ll expect by default. But, for unclear reasons, NetSuite has not bothered to implement it, leaving users with no option but to take matters into their own hands. Gladly, there is a way to achieve the desired behavior.

Solution

The Common Solution: Inject a Script via The Browser

The earliest reference I can find for this solution is a thread from 2017 on netsuitehub.com. The author apparently contacted NetSuite about the problem of non-sticky sublist headers. The suggested solution was to use a third-party browser extension to inject a script that locks the header row. A more recent 2019 article I found reproduces this idea with minor modifications.

While this solution appears to work (at least in view mode during my tests), it is impractical for several reasons. First, your IT department is not likely to approve any browser extensions that allow you to inject arbitrary scripts into a page for obvious (security) reasons. Second, if they do, chances are that your (non-technical) NetSuite users will likely find setting this up too much of a hassle. Third, if you ever have to modify the script, e.g., because NetSuite changed something, good luck with getting everyone to update their local script! Fourth, not all browsers might offer trustworthy extensions that support injecting scripts into pages. In short, a better approach is needed.

A Preferred Solution: Inject a Script from Inside NetSuite Using an Inline HTML Field

If you’ve worked long enough with NetSuite, you probably know that it is possible to inject a script/HTML into any page using NetSuite’s infamous Inline HTML field type. This field type is intended for use with Suitelets – NetSuite’s mechanism for building custom pages and backend logic. However, it is often used to overcome other challenges that are unrelated to Suitelets [I]Marty Zigman (September 22, 2018). Learn how to Hide NetSuite Sublist Buttons and Other HTML Elements. Available at … Continue reading [II]Marty Zigman (June 13, 2020). How To Stretch and Fill NetSuite Inline HTML Content. Available at https://blog.prolecto.com/2020/06/13/how-to-stretch-and-fill-netsuite-inline-html-content/ [Accessed … Continue reading. This article by Marty Zigman is a good introduction to this approach if you’re not familiar with it.

Conceptually, the solution involves the following steps:

  1. Create a User Event script in NetSuite.
  2. In the beforeLoad() function, retrieve the form to be displayed to the user and add a custom field of type Inline HTML.
  3. Set the default value of the field to the HTML script you want to be executed when the page is rendered to the end-user.
  4. Decide on which record types to deploy the script to. I’d recommend deploying it to all script types since there’s hardly any record type that will not benefit from this solution.

The general template of your User Event Script may look like this:

/**
 * @NApiVersion 2.0
 * @NScriptType UserEventScript
 * @NModuleScope Public
 */
define(['N/ui/serverWidget'],

function(serverWidget) {
	
    function beforeLoad(context) {
    	context.form.addField({
            id: 'custpage_stickyheaders_script',
            label: 'Hidden',
            type: serverWidget.FieldType.INLINEHTML
        }).defaultValue = '<script>' +
        	'(function($){' +
        	    '$(function($, undefined){' +
		         // Whatever is here will be executed after the page loads
		         // $('.uir-machine-table-container').css(...) comes here
        	    '});' +
        	'})(jQuery);' +
		'</script>';
    }
    
    return {
        beforeLoad: beforeLoad
    };
});

I have adapted the original script referenced in the previous section to solve this challenge in a more elegant manner by using a User Event Script within NetSuite. In addition to fixing some issues (for example, the original script does not work consistently in edit mode), I have made some extensions, inspired by this (paid) “product”, to support a sticky floating action bar. The final script is surprisingly compact and pretty straightforward!

I think this is a better solution as it requires no end-user configuration, and works in all major browsers (I’ve tested using Google Chrome, Mozilla Firefox, and Safari). And I’m offering it to you at no cost! However, before you head over to grab the script, it is important that you understand NetSuite’s official policy on these kinds of solutions.

A Word on DOM Manipulations in NetSuite

Whenever we use an Inline HTML field to inject our own code into a NetSuite page, we are manipulating the Document Object Model (DOM) of the page. NetSuite discourages this practice:

“NetSuite Forms does not support manipulation through the Document Object Model (DOM) and custom scripting in Inline HTML fields. The use of Inline HTML fields on Form pages (except for Forms generated by Suitelets) will be deprecated in a future release.”

SuiteAnswers (Answer Id: 10085)

In other words, there is a chance that, with a future release, NetSuite could make changes that prevent these types of solutions from working. Ironically, while NetSuite issues such strong warnings, they do not provide solutions for simple yet annoying problems like the one we’re considering, leaving us with the dilemma of choosing between the “rules” and our sanity.

My take on this is simple: Avoid DOM manipulation whenever possible. If there’s no other feasible solution, before hijacking the DOM, ask yourself: “What’s the risk my organization/client faces if this solution breaks due to a future change in NetSuite?” If that risk is acceptable, proceed cautiously and be sure to properly document and motivate your solution.

Although direct DOM manipulation is strongly discouraged in NetSuite, there are situations where that's all you've got and it's okay to cautiously tread this path. Click To Tweet

In our case, the risk is very low. If this solution breaks, NetSuite will gracefully degrade to the current state where headers are not sticky. And if for any reason, the solution is not working properly, rolling it back would be a single-click matter of deactivating the deployed script. So, for the problem at hand, the risk is clear, low, and acceptable… at least in my opinion.

Moreover, it will take a fundamental redesign of the NetSuite UI (in particular the sublist structure) or a renaming of the underlying CSS classes to break this solution. That, my friend, is possible but quite unlikely. And, again, if it does happen, a fix will be likely be very simple.

Parting Words

Both solutions described in this article inherently work for any sublist or table in NetSuite because they are based on CSS classes that are pretty ubiquitous in NetSuite. These solutions will also work for any custom tables you create (e.g. a custom HTML table in a Rich Text field) provided you apply the relevant CSS classes to it, i.e. uir-machine-table-container to the table container and uir-machine-headerrow to the header row.

It is definitely worth reiterating that DOM manipulation should always be given very careful consideration. If you find yourself reverting to this approach often, and for non-trivial, process-critical problems, go back to the drawing board; you probably need a redesign.

Finally, let me remind you that my complete solution that works both in view and edit modes (as well as for the floating action button bar during horizontal scrolling in edit mode) is just a click away.


Back at Asoville Inc., Edet has silently pushed her Sticky Headers solution to Production after careful validation. She’s now patiently waiting to see who’d be the first to notice the difference! And if no one does, that’s fine, because tables with sticky headers are the way things should be!

Other Interesting Utilities

Further Reading[+]

Chidi Okwudire IT Professional. ERP Enthusiast. NetSuite Certified (Administrator, SuiteCloud Developer II, and ERP Consultant). Celigo Certified (Level 4+). Passionate About Empowerment Through Knowledge Sharing. Always Eager to Learn.

9 Replies to “A NetSuite Sticky Headers Solution That Works”

  1. Hi Chidi, longtime follower of yours. I noticed that your solution covers up the Center menus of the native NetSuite form. I found that changing the z-index to 10 solves the issue.

    1. Hi there,

      Thanks for mentioning this. It’s tricky to know what z-index value is “right”. Someone recently mentioned they reduced to 99. You chose, 10… any reason for that choice?

  2. Thank you for this as it works great! I was just wondering if it were possible to run the script on the NetSuite ‘Order Items’ page?

    1. Hi Andrew, as NetSuite does not allow us inject scripts into such pages, this approach will not work. You might have to resort to client-side solutions e.g. using Chrome extensions. However, as explained in this article, such solutions are hard to scale across multiple users.

  3. Hello,

    Sorry for leaving a message so long after your post, but I was wondering if we can also apply this kind of userscript on saved search, in view or edit mode ? I actually have a script to fix a column depending of the position through a chrome addon (Tempermokey). it is working great so far, but would be better to have it directly on Netsuite for end users. Any idea if possible ? Below the script :

    // ==UserScript==
    // @name NetSuite Floating column v2
    // @version 2
    // @description Netsuite Floating column
    // @match https://*.netsuite.com/*
    // @require http://code.jquery.com/jquery-latest.js
    // ==/UserScript==

    (function ($, undefined) {
    $(function () {
    $(“#div__labtab td:nth-child(8)”).css(“position”, “sticky”).css(“left”, “0px”).css(“z-index”, “1”).css(“overflow”, “hidden”);
    $(“#div__bodytab td:nth-child(8)”).css(“position”, “sticky”).css(“left”, “0px”).css(“z-index”, “1”).css(“overflow”, “hidden”);

    });
    })(window.jQuery.noConflict(true));

    1. Hi, as far as I know, there’s no way to do this natively in NetSuite as the saved search results page (like pretty much all native lists) are not scriptable. You’d probably need to stick with an addon. Cheers.

  4. Hello,

    Thank you so much for publishing this article. Does this solution works in edit/create context type of a transaction to freeze header columns?

    1. Hi Sankar,

      You’re welcome. Yes, the solution works in edit/create mode as well.

      Cheers.

Leave a Reply

Your email address will not be published. Required fields are marked *

×