In NetSuite Suitelets, enhancing the user interface with interactive features can significantly improve user experience. One such enhancement involves dynamically displaying column labels when interacting with a sublist. In this tutorial, we will explore how to use a Client Script attached to a Suitelet to display column labels when hovering or focusing on sublist cells.
This feature is useful in providing clear visibility of column headers when working with long data entries or sublists, ensuring users can easily track data against the right labels.

Step-by-Step Guide to Displaying Column Labels in a Suitelet
1. Creating a Suitelet with a Sublist
Before implementing the client-side functionality, ensure that you have a Suitelet that generates a sublist. This sublist will have rows and columns of data for which the dynamic label display will be applied.
Here’s a simple example of how to create a Suitelet and attach a sublist:
define(['N/ui/serverWidget'], function(serverWidget) {
function onRequest(context) {
if (context.request.method === 'GET') {
var form = serverWidget.createForm({ title: 'Sample Suitelet Sublist' });
var sublist = form.addSublist({
id: 'custpage_sublist',
type: serverWidget.SublistType.LIST,
label: 'Sample Sublist'
});
sublist.addField({
id: 'custpage_column1',
type: serverWidget.FieldType.TEXT,
label: 'Column 1'
});
sublist.addField({
id: 'custpage_column2',
type: serverWidget.FieldType.TEXT,
label: 'Column 2'
});
context.response.writePage(form);
}
}
return {
onRequest: onRequest
};
});
2. Writing the Client Script to Display Column Labels
Now, we will attach a Client Script that dynamically shows column labels on focus or hover over sublist cells. The script achieves this by attaching event listeners to each cell in the sublist, making the label appear when hovering or clicking on the input fields.
Client Script:
/**
* @NApiVersion 2.1
* @NModuleScope Public
* @NScriptType ClientScript
*/
import { EntryPoints } from "N/types";
import * as log from 'N/log';
/**
* Initialize display column label function.
* @param context
*/
export function pageInit(context: EntryPoints.Client.pageInitContext): void {
try {
displayColumnLabel(); // Initialize the function when the page loads
} catch (error) {
console.error('pageInit error: ', error);
}
}
/**
* Returns HTML of label box.
* @param pTable - HTML element object of table
* @param pCell - HTML element object of the cell
* @returns HTML Element
*/
const getLabelHtml = (pTable, pCell) => {
const cellIndex = pCell.cellIndex;
const cellHeight = pCell.parentElement.clientHeight;
const header = pTable.rows[0].cells[cellIndex].innerText; // Extract header text
const cellRect = pCell.getBoundingClientRect(); // Get cell position for accurate label placement
let hoverHtml = document.createElement("div");
// Dynamically create a small label box to display the header
hoverHtml.innerHTML = `
<div id="headerText" style="
border: 0.5px solid black;
width: fit-content;
padding: 4px;
background-color: #fffff2;
z-index: 1;
position: fixed;
top: ${cellRect.top + (cellHeight / 2)}px;
left: ${cellRect.left}px;
">
${header.trim()}
</div>
`;
return hoverHtml;
};
/**
* Removes the label box from the DOM.
*/
const removeLabelHtml = () => {
const getHoverHtml = document.getElementById('headerText');
if (getHoverHtml) {
getHoverHtml.remove(); // Remove the label box when not needed
}
};
/**
* Show column label on click, initialize on pageInit function.
*/
const displayColumnLabel = () => {
const cellArr = document.getElementsByClassName('uir-list-row-cell'); // Get all sublist cells
const table = document.getElementById('sublist_splits') as any; // Reference to the sublist table
for (let i = 0; i < cellArr.length; i++) {
let cell = cellArr[i] as any;
// Add event listener for input field focus
const inputField = cell.getElementsByTagName('input')[0];
if (inputField) {
inputField.onfocus = () => {
removeLabelHtml(); // Clear previous label if any
const hoverHtml = getLabelHtml(table, cell); // Get new label HTML
cell.appendChild(hoverHtml); // Append the label to the cell
};
inputField.onblur = removeLabelHtml; // Remove label when the input loses focus
}
// Show label when mouse hovers over a cell
cell.onmouseover = function () {
removeLabelHtml();
const hoverHtml = getLabelHtml(table, cell);
this.appendChild(hoverHtml);
};
// Remove label when mouse leaves the cell
cell.onmouseleave = removeLabelHtml;
}
};
⚠️ Warning: The code in this example is written in TypeScript. If you’re unfamiliar with setting up SuiteScript using TypeScript or want to learn more, you can visit this post for a step-by-step guide on configuring your environment.
If you prefer to use JavaScript, you can find the JavaScript version of the script below:
JavaScript version of the script
/**
* @NApiVersion 2.1
* @NModuleScope Public
* @NScriptType ClientScript
*
*/
define(["N/log"], function (log) {
/**
* Initialize display column label function.
* @param context
*/
function pageInit(context) {
try {
displayColumnLabel();
} catch (error) {
console.error('pageInit error: ', error);
}
}
/**
* Returns HTML of label box
* @param pTable - HTML element object of table
* @param pCell - HTML element object of the cell
* @returns
*/
const getLabelHtml = function(pTable, pCell) {
const cellIndex = pCell.cellIndex;
const cellHeight = pCell.parentElement.clientHeight;
const header = pTable.rows[0].cells[cellIndex].innerText;
const cellRect = pCell.getBoundingClientRect();
let hoverHtml = document.createElement("div");
hoverHtml.innerHTML = `
<div id="headerText" style="
border: 0.5px solid black;
width: fit-content;
padding: 4px;
background-color: #fffff2;
z-index: 1;
position: fixed;
top: ${cellRect.top + (cellHeight / 2)}px;
left: ${cellRect.left}px;
">
${header.trim()}
</div>`;
return hoverHtml;
};
const removeLabelHtml = function() {
const getHoverHtml = document.getElementById('headerText');
if (getHoverHtml) {
getHoverHtml.remove();
}
};
/**
* Show column label on click, initialize on pageInit function.
*/
const displayColumnLabel = function() {
const cellArr = document.getElementsByClassName('uir-list-row-cell'); // Cell HTML class
const table = document.getElementById('sublist_splits'); // Sublist table HTML ID (sublist ID + '_splits')
for (let i = 0; i < cellArr.length; i++) {
let cell = cellArr[i];
// Add event on input field focus
const inputField = cell.getElementsByTagName('input')[0];
if (inputField) {
inputField.onfocus = function() {
removeLabelHtml();
const hoverHtml = getLabelHtml(table, cell);
cell.appendChild(hoverHtml);
};
inputField.onblur = removeLabelHtml;
}
// Add event on cell click
cell.onmouseover = function() {
removeLabelHtml();
const hoverHtml = getLabelHtml(table, cell);
this.appendChild(hoverHtml);
};
// Remove label hover HTML on mouse leave
cell.onmouseleave = removeLabelHtml;
}
};
return {
pageInit: pageInit
};
});
3. Explanation of the Key Functions
- pageInit(): This function is called when the page initializes. It ensures that the displayColumnLabel() function is triggered, which attaches the necessary events to the sublist cells.
- getLabelHtml(): This helper function generates the HTML for the label that will be displayed. It calculates the position of the cell and places the label in an appropriate position relative to the cell.
- removeLabelHtml(): This function removes the label from the DOM when it’s no longer needed (e.g., when the mouse leaves the cell or the input field loses focus).
- displayColumnLabel(): This function is the core logic that attaches event listeners (onfocus, onmouseover, and onmouseleave) to the sublist cells. It dynamically shows the label when required.
4. How It Works
- When the page is loaded, the pageInit() function is triggered, which sets up event listeners on all sublist cells.
- When a user hovers over a sublist cell or focuses on an input field within the sublist, the label corresponding to that column header is dynamically displayed.
- The label box is removed when the mouse leaves the cell or the input field loses focus.
5. Attaching the Client Script to the Suitelet
To attach the client script to the Suitelet, ensure you link it in the Suitelet’s onRequest method:
form.clientScriptModulePath = 'path/to/your/clientscript.js'; // Attach the Client Script
Conclusion
With this Client Script implementation, you can significantly enhance the interactivity of sublists in your Suitelets by dynamically displaying column labels. This makes it easier for users to interact with sublists containing multiple columns, ensuring they always know the context of the data they are entering or viewing.
For further customizations, you can expand this functionality to include more complex tooltips, customized styling, or additional events to improve the user experience even more.