[UI Builder] How to Trigger Smooth Auto-Scroll in Repeater Container After Chat Update?

HarinisriK05649
ServiceNow Employee
ServiceNow Employee

Hi Community,

I'm building a chat interface in UI Builder, where each user query and bot response is stored in a "chatHistory" client state parameter (array) and rendered using a Repeater inside a container.

The container has:

max-height: 600px;
overflow-y: auto;

 

Every time a new message is added, I want the chat container to automatically scroll to the bottom, so the latest message is visible without manual scrolling.

What’s the best way to achieve this in UI Builder?
Would appreciate any guidance or suggestions!

Thanks in advance!

 

 

7 REPLIES 7

Mark Dooley
Tera Contributor
Similar issue...what I did in UI Builder was first select the container that holds my chat messages—basically the outer wrapper around the repeater that renders each message. This container already had max-height: 600px and overflow-y: auto set so it can scroll. I gave it a View Reference name so I could access it in a script. I just named it "chatScrollContainer"  Then, I went to the Client Scripts section and created a new one. I set the trigger type to "onStateChange" for the state parameter to watch, I selected "chatHistory" That’s the array where each new message (user or bot) gets pushed. Inside the script, added this code:
 
api.state.chatHistory.subscribe(() => {  
// Wait for DOM to update  
setTimeout(() => {    
const container = api.view.getViewElement('chatScrollContainer');    
if (container) {      
container.scrollTop = container.scrollHeight;    
}
 }, 100); // Delay ensures new message is rendered before scrolling
});
 
What this does is, every time "chatHistory" updates (like when a new message is added), it waits 100 milliseconds just to give the DOM time to render the new content. Then it grabs the container using the View Reference name we set earlier and scrolls it to the bottom using "scrollTop = scrollHeight" every time a new message comes in, the chat should scroll all the way down automatically so users always see the latest message. Smooth and no need for any weird DOM workarounds outside UI Builder.

Hi @Mark Dooley 

Thank you for responding!

Could you please clarify a few things? What is the View Reference Name — is it the same as the Component ID?
In the client script, we have the option Trigger by, but where is Trigger Type? How do we select it?

Could you please share the steps?



I am getting "'setTimeout' is not defined." error

Mark Dooley
Tera Contributor
Hey there! Apologies if things weren’t super clear before – let me try to break it down in a way that’s a bit easier to follow
 
  1. View Reference Name vs. Component ID: Okay, so the View Reference Name is like giving your component a cool nickname so you can call it by that name in your script. For example, I called my chat container “chatScrollContainer” because, well, it’s exactly what it does. This is different from the Component ID, which is a name the system gives the component automatically (and let's face it, that’s usually a mess of numbers and letters that no one remembers).  You set the View Reference Name manually in the properties panel of the component. You’ll use that name in your code. 
  2. Steps to set up the View Reference Name:
    1. Click on your chat container in UI Builder.
    2. In the properties panel, look for View Reference Name and give it a name (something memorable like "chatScrollContainer").
    3. In your script, just use that name to grab the container, like this: api.view.getViewElement('chatScrollContainer').
  3. Trigger Type: The Trigger Type is kind of like setting an alarm clock for your script as it tells it when to wake up and do its job. In this case, we want it to wake up every time the chatHistory state changes (a new message!).
    Steps to select the Trigger Type:
    1. Go to the Client Scripts section in UI Builder.
    2. Create a new script (or edit an existing one).
    3. In the "Trigger by" section, pick State Change (that’s when the chat history updates).
    4. In the "Trigger Type" dropdown, select onStateChange.
    5. Then select chatHistory from the list of states to watch.
Now, about that setTimeout error you're seeing......it might be that setTimeout isn’t available in your script environment by default, so you’ll want to use window.setTimeout() instead. A little tweak, and you should be back in business
Here’s your updated code:

 

 
api.state.chatHistory.subscribe(() => {    
// Wait for DOM to update    
window.setTimeout(() => {  // Use window.setTimeout to make sure it works in this context    
const container = api.view.getViewElement('chatScrollContainer');        
if (container) {            
container.scrollTop = container.scrollHeight;        
}
}, 100); // Delay gives the DOM time to render the new message before scrolling
});
 
I think that should take care of the error now for you