This article presents a free, versatile NetSuite split pane utility that will supercharge your (users’) NetSuite experience. It also includes sample code snippets to get you going. NetSuite Insights would like to thank the author for generously providing this capacity to the community at no cost.
Table of Contents
Background
While working on a custom approval Suitelet, I encountered a challenge related to the efficiency of the approval process using this approach. The Suitelet contained a list of transactions along with their respective details for the approver to review. However, despite having most of the necessary information within the Suitelet, the existing workflow still proved to be cumbersome. Opening each transaction in a new tab to verify additional details and then switching back to the Suitelet was not only time-consuming but also disrupted the intended seamless flow of the approval process.
Recognizing the need for a more streamlined approach, I was motivated to come up with a solution that would enhance the user experience for the approver. My goal was to develop a library that would allow transactions to be easily viewed and assessed on the same page, eliminating the need for constant tab-switching. I succeeded!
As I focused on improving the approval process, I realized that the library had potential beyond just approvals. I found that its features could be applied to other scenarios as well, such as loading relevant links in the pane view on page load. This realization motivated me to make the library more versatile, catering to a wider range of business needs.
Example Use Cases
There are several scenarios in which the split pane utility can add value. Here are my favorite ones.
Use Case 1: Loading a preview of a transaction in PDF format on page load
Users may want to immediately see the PDF format of the current transaction in edit/view mode. To close the split pane, they can easily drag it to the leftmost side of the page or double-click on the bar/divider.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/runtime'], (runtime) => {
/**
* Function definition to be triggered before the record is loaded.
*
* @param {Object} context
*/
const beforeLoad = (context) => {
try {
instantiateSplitPane(context);
} catch (err) {
log.error({
title: err.name,
details: err.message,
});
}
};
/**
* Instantiates the Split Pane view through a User Event Script
*
* @param {Object} context
*/
const instantiateSplitPane = (context) => {
if (runtime.executionContext !== runtime.ContextType.USER_INTERFACE) {
return;
}
const allowedTypes = [context.UserEventType.EDIT, context.UserEventType.VIEW];
if (context.type.includes(allowedTypes)) {
return;
}
const recordId = context.newRecord.id;
const pageLink = `/app/accounting/print/hotprint.nl?regular=T&sethotprinter=T&formnumber=92&trantype=custinvc&&label=Invoice&printtype=transaction&id=${recordId}`;
const splitPaneHTML = context.form.addField({
id: 'custpage_hex_splitpane',
label: 'Split Pane',
type: 'inlinehtml',
});
splitPaneHTML.defaultValue = `
<script>
require(['SuiteScripts/HEX_LIB_SplitPane.js'], (splitPane) => {
splitPane.openSplitPane('${pageLink}', 30);
});
</script>`;
};
return {
beforeLoad,
};
});
Use Case 2: Loading a record’s attachment in the split pane on button click
In certain cases, users may prefer the option to open the split pane view only when necessary. To accommodate this scenario, a button can be added through a user event script to open the split pane.
Here’s a sample code for the use case illustrated above.
/**
* @NApiVersion 2.1
* @NScriptType UserEventScript
*/
define(['N/runtime'], (runtime) => {
/**
* Function definition to be triggered before record is loaded.
*
* @param {Object} context
*/
const beforeLoad = (context) => {
try {
context.form.addButton({
id: 'custpage_hex_splitpane',
label: 'Open Most Recent Attachment',
functionName: 'openMostRecentAttachment',
});
context.form.clientScriptModulePath = 'SuiteScripts/HEX_CS_Invoice.js';
} catch (err) {
log.error({
title: err.name,
details: e.message,
});
}
};
return {
beforeLoad,
};
});
Here’s the client script referenced in the user event script above:
/**
* @NApiVersion 2.1
* @NScriptType ClientScript
*/
define(['N/currentRecord', 'N/search', 'SuiteScripts/HEX_LIB_SplitPane.js'], (
currentRecord,
search,
splitPane
) => {
/**
* Function to be executed after page is initialized.
*
* @param {Object} context
*/
const openMostRecentAttachment = () => {
const currentRec = currentRecord.get();
const fileURL = getMostRecentAttachmentURL(currentRec.id);
try {
splitPane.openSplitPane(fileURL);
} catch (err) {
console.log(err);
}
};
/**
* Retrieves the most recent attachment of the current invoice record
*
* @param {Object} context
*/
const getMostRecentAttachmentURL = (invoiceId) => {
const fileSearch = search
.create({
type: search.Type.INVOICE,
filters: [
search.createFilter({
name: 'internalid',
operator: search.Operator.ANYOF,
values: [invoiceId],
}),
search.createFilter({
name: 'mainline',
operator: search.Operator.IS,
values: ['T'],
}),
],
columns: [
search.createColumn({name: 'url', join: 'file'}),
search.createColumn({
name: 'created',
join: 'file',
sort: search.Sort.DESC,
}),
],
})
.run()
.getRange({start: 0, end: 1});
const fileURL = fileSearch[0]?.getValue({name: 'url', join: 'file'});
return fileURL;
};
return {
pageInit: () => {},
openMostRecentAttachment,
};
});
Use Case 3: Loading records in the split pane through a Suitelet link
When creating Suitelets containing a list of records, it is a common practice to include a column containing a link to the respective record for users to view. This use case is exhibited in the background section of this article.
To enhance the user experience, we can allow users to conveniently access and view these records within the same page through the split pane.
searchObj.run().each((result) => {
const docNumber = result.getValue({ name: 'tranid' });
const url = `/app/accounting/transactions/transaction.nl?id=${result.id}&ifrmcntnr=T`;
sublist.setSublistValue({
id: 'custpage_document_number',
line: i,
value: splitPane.generateLink(docNumber, url), // Defaults to 50% width
});
...
});
Once the generateLink
function has been invoked, it will create a href
element that contains an inline onclick
event handler. This event handler is responsible for opening the link within the split pane view. In the event of an unexpected error within the library, the generated link will revert to the default behavior of an href tag.
It is important to consider that the
TEXT
field type has a maximum character limit of 300. In certain cases, the generated link may exceed this limit due to factors such as the length of the label name and the URL, and the inline event handler embedded within the link. To prevent exceeding the limit, I recommend using theTEXTAREA
field type instead.
Considerations
Document Object Model (DOM) Manipulation
The Split Pane library operates on the client side, utilizing DOM manipulation to build the split pane. Although this approach can be seen as a “hack”, as NetSuite discourages direct DOM manipulation due to potential breaking changes caused by internal product updates, we can mitigate the associated risks by implementing precautionary measures such as enclosing function calls in a try-catch block.
Theme Inheritance
For a better user experience (UX), the library was designed to adopt the color theme of the user as specified in the User Preferences.

To implement this, I initially considered using the N/config
module to fetch the user’s color theme preference and apply it to the elements of the split pane. However, since the library operates on the client side and the module is only accessible on server side, this approach was not feasible. As an alternative solution, I came up with the idea of retrieving the color of the navigation bar, which is present on most, if not all, NetSuite pages, using the following code snippet.
const navbar = document.getElementsByClassName('n-w-header__navigation')[0];
const barColor = navbar ? window.getComputedStyle(navbar).backgroundColor : '#444444';
It is important to mention that if the element does not exist for various reasons, such as NetSuite updating the element selector, the library will default to using the color #444444
. The provided code snippet is flexible and useful when you want certain elements to match the user’s current theme.
Conclusion
Despite the library’s seemingly simplistic nature, its potential to significantly reduce the time and effort invested by users is remarkable. As these time savings accumulate, they can result in exponential gains in productivity. Its simplicity belies its true power, making it an invaluable tool for developers and NetSuite users seeking enhanced efficiency and productivity.
How to Get the Split Pane Utility
I am happy to share this utility for free under the MIT license with anyone who needs it. Head over to my Github project to download the single file source code. Feel free to use it in your personal and commercial products per the license conditions. As a courtesy to the community, be sure to share any useful enhancements with the community, for example via merge requests in Github.
NetSuite Insights is on a mission to raise the standards around NetSuite practices, one insight at a time. If that resonates with you, learn how you can become an author/collaborator here.
Don’t miss a beat – subscribe to our no-nonsense email list to have these game-changing insights hit your inbox as soon as they’re published. Ignorance? Nah, you’ve got a smarter option. Choose wisdom, choose insights!
Do I need to add anything to the Use Case 3 code, or is it complete as it is?
The code provided in Use Case 3 is only a portion of the Suitelet script that may require modifications to suit your specific use case.
You haven’t created a User Event script that makes use of the library only the library file.
You need to re-read and understand how this works the library on it’s own in the file cabinet does nothing.
I tried, these steps yet didn’t work for me:
Download the HEX_LIB_SplitPane.js file from the GitHub repository.
Upload the file in the NetSuite File Cabinet.
Update the PANE_LIB_PATH section in the file to match the correct file directory where the library is located. By default, the location is set to the root directory of the SuiteScripts folder.
Edit Invoice->tried moving the screen with holding mouse but nothing, kindly advice what I am doing wrong.
Chidi, this is awesome! I don’t think we can get this to fire from a saved search result list, though, right?
Marty Zigman
Yes! I was excited to stumble upon this utility. I don’t think we can get this to work for saved searches as we need a way to “hook into” the page and those native lists don’t offer entry points. That said, I’ll ask Howell if he has any ideas.
Thank you, Marty!
Unfortunately, we cannot trigger the split pane within the saved search results view. On a positive note, I’m actively working on the development of a Chrome Extension that aims to enable the split pane functionality for a majority, if not all, of the NetSuite links or buttons.
Very cool solution. Great job!