Set UI customization configuration
When configuring user interface (UI) customization, provide the settings in the ui option when you load the SDK:
NutrientViewer.load({ // ... Your configuration. ui: { // Initial configuration for UI customization. },});You may also want to update the UI customization configuration after the SDK has been loaded. Use the setUI method on instance to do so.
Updating the UI configuration
With setUI, you can update any of the slots in your UI customization configuration. This also applies to nested slots.
Consider the following example where you’re customizing the commentThread slot:
NutrientViewer.load({ // ... Your configuration. ui: { commentThread: (getInstance, id) => ({ render: (params) => { // Return a DOM node. const div = document.createElement("div"); div.style.backgroundColor = "lightblue"; div.style.padding = "10px"; div.style.border = "1px solid #ccc"; div.style.borderRadius = "5px"; div.innerText = `This is a custom UI for the comment thread: ${id}`;
return div; }, }), },});Later, if you want to update the commentThread slot to change its content, you can do so with instance.setUI:
instance.setUI({ commentThread: (getInstance, id) => ({ render: (params) => { // Return a DOM node. const div = document.createElement("div"); div.style.backgroundColor = "lightblue"; div.style.padding = "10px"; div.style.border = "1px solid #ccc"; div.style.borderRadius = "5px"; div.innerText = `Updated content for comment thread.`;
return div; }, }),});Updating nested slots
Nested slots can be updated the same way.
Note that you need to provide the full configuration object to setUI. The provided object replaces the entire configuration passed in the ui option during SDK load.
Consider the following example where you’re customizing the header slot within the commentThread slot:
NutrientViewer.load({ // ... Your configuration. ui: { commentThread: { header: () => { return { render: () => { const div = document.createElement("div"); div.style.backgroundColor = "lightgreen"; div.style.padding = "5px"; div.innerText = "This is a custom header for the comment thread.";
return div; }, }; }, }, },});Later, if you want to remove the header customization and add footer customization at the same time, you can do so with instance.setUI:
instance.setUI({ commentThread: { footer: () => { return { render: () => { const div = document.createElement("div"); div.style.backgroundColor = "lightcoral"; div.style.padding = "5px"; div.innerText = "This is a custom footer for the comment thread.";
return div; }, }; }, },});Partially updating the UI configuration
The configuration object you pass to setUI completely replaces the previous configuration. But you may want to update only specific slots while leaving the rest of the UI intact.
To do this, store your UI configuration in a variable before passing it to the ui property in load. When passing an updated configuration to setUI, build a new object by merging your previous configuration with the new changes. Keeping references to unchanged slots intact tells the SDK not to update them.
Pass a new object to setUI instead of mutating the previous configuration object so that the SDK can reliably detect changes.
Suppose you’ve customized the header and footer slots within the commentThread slot:
// Instead of directly passing the object to the `ui` property, store it in a variable first.const uiConfig = { commentThread: { header: () => { return { render: () => { const div = document.createElement("div"); div.style.backgroundColor = "lightgreen"; div.style.padding = "5px"; div.innerText = "This is a custom header for the comment thread.";
return div; }, }; }, footer: () => { return { render: () => { const div = document.createElement("div"); div.style.backgroundColor = "lightcoral"; div.style.padding = "5px"; div.innerText = "This is a custom footer for the comment thread.";
return div; }, }; }, },};
NutrientViewer.load({ // ... Your configuration. ui: uiConfig,});To update the footer slot within commentThread while keeping the header slot intact, merge your previous configuration with the new changes:
instance.setUI({ // Spread the previous configuration to keep unchanged slots intact. ...uiConfig, commentThread: { // Spread the previous `commentThread` configuration to keep unchanged slots, such as header, intact. ...uiConfig.commentThread, footer: () => { return { render: () => { const div = document.createElement("div"); div.style.backgroundColor = "lightcoral"; div.style.padding = "5px"; div.innerText = "Updated content for the custom footer.";
return div; }, }; }, },});Grouped slots
Grouped slots follow the same pattern. Pass the full nested structure to setUI — the new configuration completely replaces the previous one:
// Hide annotation actions and replace the delete confirmation at runtime.instance.setUI({ annotations: { actions: (getInstance, id) => ({ render: () => null }), deleteConfirm: (getInstance, id) => ({ render: () => { const div = document.createElement("div"); div.textContent = "Are you sure you want to delete?"; const btn = document.createElement("button"); btn.textContent = "Confirm"; btn.onclick = async () => { const instance = getInstance(); if (!instance) return; const selected = instance.getSelectedAnnotations(); if (selected?.size) await instance.delete(selected.first().id); }; div.appendChild(btn); return div; }, }), },});Presets at runtime
You can apply or remove a preset at runtime:
// Switch to minimal (canvas-only) mode:instance.setUI({ preset: 'minimal' });
// Minimal mode with only search visible:instance.setUI({ preset: 'minimal', search: (getInstance, id) => ({ render: () => { const div = document.createElement("div"); div.textContent = "Custom search"; return div; }, }),});
// Reset to full default UI:instance.setUI({});