Update progress bar realtime?

I created a “sp-progressbar” element within my plugin, but I want to update the value of the progress bar and be able to see the progression in realtime which I can’t.

I update the progressBar.value = SOMEVALUE inside a function, but it doesn’t updates anything on the UI until this function is done, so how could I update the progressBar.value and be seen in the UI while the function is processing?

Hope this makes sense.

Would you mind sharing that piece of code?

Have you tried adding a small delay after your update? You may have to yield to the UI for a short amount of time so it has a chance to update. It’s not the most elegant thing in the world but it has done the job for me.

Delay isn’t an option for me as my primary goal is to optimize speed performance for the plugin update on each new setting value, nevertheless using a “setTimeOut()” function does the job, works with 300ms but 300ms for my update speed are crucial haha!

My main function is inside of a suspendHistory function:

As it is a long code, this is some example of how it works:

const progressBar = document.createElement("sp-progressbar");
progressBar .value = 0;
progressBar .max = 100;

suspendHistory("Update settings", updateSettings);

async function updateSettings() {
progressBar.value = 0;

await someFunction();
progressBar.value = 10;
await someFunction();
progressBar.value = 20;
await someFunction();
progressBar.value = 30;
await someFunction();
progressBar.value = 40;
await someFunction();
progressBar.value = 50;

//... and so on until progressBar.value = 100;

const suspendHistory = async (theSuspendName, functionName) => {
  await executeAsModal(doStuff, { "commandName": "Please Wait" });

  async function doStuff(executionContext) {
    let hostControl = executionContext.hostControl;
    let documentID = await app.activeDocument._id;
    // Suspend history state on the target document
    let suspensionID = await hostControl.suspendHistory({
      "historyStateInfo": {
        "name": theSuspendName,
        "target": [{ _ref: "document", _id: documentID }]
    //	 console.log(functionName);
    await executeAsModal(functionName, {});

    await hostControl.resumeHistory(suspensionID);

The progressBar element is updated but only when the updateSettings function is done.

The idea is that I want the progressBar to be updated with each “someFunction()” function so the user can feel the progress and that gives the brain the idea that it is progressing and not just a before and after, if that makes sense.

Does it work without history suspension? Do you really need here double exeModal (one inside another)? Could you share a reproducible code so that other could just copy into console or html playground plugin and see the issue? (help others help you :slight_smile:)


Wouldn’t it simpler to rely on executeAsModal’s progress bar instead of creating your own?
You have to work within a modal context anyway, and history states can be suspended there.

The executionContext.reportProgress({value:String}) function can be then used to update the progress bar (see here for the docs).

I’m not sure what’s wrong with your code (something to do with closures maybe? Also the nested executeAsModal isn’t necessary, and your call to suspendHistory possibly needs an await).


For what it’s worth in my experience the executeAsModal’s progress bar has an even worse update behavior. I had reported this in a topic a while ago (Using progressReport to update displayed text in progress bar

With CEP I used to have a really cool loading spinner animation, I don’t know why we are limited to create our own animations with CSS. @kerrishotts CSS animations is something that would be implemented in the future for UXP? Or something that we can customize a little bit more our plugins?

For what it’s worth in my experience the executeAsModal’s progress bar has an even worse update behavior.

The bug seems to have been logged (Cc @Erin_Finnegan: it’s PS-86916)


Thanks for the sugestion of the nested execudeAsModal, I totally agree, I just copied and paste it from other post but didn’t realized it had a nested executeAsModal until now, thank you!

I also just tried the next code inside the suspendHistory function and worked perfectly to have a real-time progress bar:

executionContext.reportProgress({"value": 1, "commandName": "Updating Oniric"});

I’ll test it with my beta testers to see how they feel this progress bar and see if it is not very invasive on the canvas. As a UI / UX designer I think it would be a better experience to have it inside the plugin itself like a small progress bar on the bottom, that’s why I wanted to make my own progress bar, but the executeAsModal progressBar works just perfect to show the update progress.

Thanks for the suggestion about the execute as modal, I just realized it had it nested, I appreciate it!, I’ve tried even without the suspendHistory doesn’t work and gives me the same results.