Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.

Follow publication

Everything That Went into Creating the First-Ever UXP-Based Plugin for Adobe InDesign

Zuri Klaschka (they/them)
Adobe Tech Blog
Published in
9 min readAug 30, 2023
Text on colorful background: Creating the first-ever UXP based plugin for Adobe InDesign
Title image created with the new Adobe Express

“The important thing is not to stop questioning. Curiosity has its own reason for existing.” — Albert Einstein

InDesign recently launched the capability to extend it with plugins built in UXP in version 18.5.

I tend to convert the first “hello world” testing projects I create into real projects, and those often turn out to be my best-performing products. And that’s how I accidentally launched the first-ever UXP plugin for Adobe InDesign that went live in the Adobe Marketplace (also known as Adobe Exchange) on Friday, August 18th, 2023.

So how did this happen?

“A long time ago, actually never, and also now, nothing is nowhere. When? Never. Makes sense, right?” — Bill Wurtz

Every seasoned professional who’s ever wielded Adobe InDesign knows its extensibility has been pivotal since before version 18.5.

InDesign’s success owes much to the invaluable scripts that have woven efficiency into workflows. And many developers make a living by creating (often very intricate) scripts for InDesign. So what’s new?

Previously, scripts and the equivalent of plugins (extensions) had to be developed using ExtendScript and CEP, respectively.

While potent, these tools posed challenges. They demanded significant effort to master, were somewhat dated (especially ExtendScript), didn’t allow for modern JavaScript best practices, and so on.

Enter stage left: UXP.

First introduced into Adobe XD in 2018, the Unified Extensibility Platform is Adobe’s answer to a more modern extensibility engine.

Although skepticism surfaced within the developer community (as is customary with migrations 😜), most can at least admit that UXP is much easier and more intuitive to learn. UXP is now integrated into XD, Photoshop, and (hot off the press) also InDesign.

And that’s where I enter the stage.

In 2018, I developed and published the Lorem Ipsum plugin for Adobe XD. Fresh out of high school, this led me on an incredible journey that included co-hosting plugin development workshops, contributing to various open-source projects in this space, and for the past two years, being employed as a working student at Adobe, advocating on behalf of developers and overall improving the developer experience of Adobe’s extensibility platforms.

That employment, unfortunately, ended in June this year. But perfectly in time, UXP plugins for InDesign are now a thing I can dig into 😁. So here we are.

The development Process

Before we dive deeper into it, I’ll quickly mention that you can check out the whole plugin’s source code on GitHub if you’re interested:

As I already wrote, the idea for the plugin actually stemmed from my first attempt at building an InDesign plugin.

Two weeks ago, I was designing a document for a queer rights activism group at the university I study at. And with that came the need to insert (adjustable) pride flags into the document several times.

Now, a normal person would probably just do this manually. But me being the tinkerer I am, I thought that it shouldn’t be too difficult to do with a plugin.

This led me on a journey to learn how to build plugins for InDesign (something I had planned to do in the next few weeks anyway, by the way). I wanted to create a plugin that would make it easy to insert pride flags in a way that’s natively integrated (instead of inserting stock images) with adjustable layers, like so:

Mostly, the development of the plugin went really smoothly. However, as with any new system you have to get used to, there were also a bunch of challenges that (until I could figure them out) felt like roadblocks.

I want to share three of the main challenges I faced, hoping they’ll help other newcomers to InDesign plugin development using UXP:

Getting used to a “new” (old) DOM and Coordinate System

The first challenge was getting used to the DOM (document object model, the representation of the document contents in code). The good news for InDesign devs from ExtendScript is that the APIs are mostly the same. The only difference is that now, previously global variables have to be imported from the InDesign module:

const { app, Rectangle } = require('indesign');

However, being new to developing for InDesign meant learning the (feeling somewhat dated) philosophy of the InDesign DOM.

For example, instead of all children being grouped in one property, child objects of groups or pages in InDesign seem to be grouped by type. For example, “rectangles”.

page.rectangles.add(...)

Thankfully, I found an excellent cheat sheet for understanding the DOM created by Gregor Fellenz, which helped immensely to make sense of the basic DOM structure.

(Gregor, you’re amazing! 😊)

Additionally, his API reference page is also extremely useful when looking up APIs (while the Adobe documentation has some great guides, the API reference section for the InDesign DOM is … barely usable).

Another thing that took some time to get used to is InDesign’s coordinate system.

In the XD world (where the DOM is actually called scenegraph), coordinates make a lot of intuitive sense, since you have:

  • a position consisting of x- and y-coordinates, describing how far an object (a node) is moved right and down from the top-left corner of its parent, respectively. I.e., something positioned at { x: 0, y: 0 } is in the top-left corner of its parent
  • a size, consisting of width and height (which are self-explanatory)

But InDesign does things a bit differently. It uses the distance from the top-left corner of the document as coordinates, just like XD.

However, instead of specifying width and height, it gives coordinates for the bottom-left corner of the object, going counter-clockwise, starting from the top.

Visualization of the InDesign coordinate system, consisting of an object’s distance to the (top-left) origin of the the page of (in this order, going counter-clockwise) the top, left, bottom, and right edge.
InDesign’s coordinate system (or “bounds” system) visualized

Here’s where my brain did a little twist. I’m used to x and y coordinates being the first and second elements, respectively.

At one point, I spent about six hours scratching my head over something that seemed totally logical. My code looked like this:

const x = bounds[0];
const y = bounds[1];
const width = bounds[2] - bounds[0];
const height = bounds[3] - bounds[1];

Over these six hours, I rehashed, re-read, and looped back, convinced “This makes sense!” After a long while, the epiphany struck. My intuition had spun me around, interchanging width and height unknowingly, and mixing up the indices of x and y coordinates.

I could have saved face here by glossing over the amount of time it took to untangle this puzzle. However, every developer knows these tales all too well.

It’s part of the process. And it’s important to talk about them, so we all know it’s not just us!

Batch edits into a single, undoable step

Another major challenge I tackled was consolidating multiple edits into a single, undoable step.

In the past, edits were treated as individual actions, causing each step of creating the pride flag (like adding rectangles, resizing, applying colors, grouping elements, and so on) to appear as separate actions in the undo history.

This required users to undo each step sequentially, which wasn’t very user-friendly.

Thankfully, I found a solution in the form of an ExtendScript forum post by Dirk Becker from 2019, pointing me in the direction of a function called “app.doScript”:

const { app, ScriptLanguage, UndoModes } = require('indesign');

app.doScript(() => {
// make edits to the document
}, ScriptLanguage.UXPSCRIPT, [], UndoModes.ENTIRE_SCRIPT, 'do XYZ');

It’s “as easy as that”. However, until I found this method, I was stumped (I didn’t want to release a plugin where you can’t conveniently undo something added in a single click with just as little effort).

Handling many edge cases

Compared to XD, InDesign presents more intricate plugin development challenges due to its age and complexity.

Consequently, our plugin must gracefully handle these scenarios, which is an something that I (as an XD plugin developer) had to learn.

Consider this code snippet for validating selections prior to action:

if (app.selection.length === 0) {
modeAlertContainer.classList.remove('alert__invalid');
mode.textContent = 'Creating a new page (nothing selected)';

return 'new';
}

Although this code seems straightforward for managing selections, a notable complication arises:

Imagine a scenario with no open documents. In InDesign, relying solely on the provided code can trigger an Error when calling app.selection. This occurs due to the absence of an open document context for the code to operate within.

To avoid this issue, a cautious approach is warranted before dealing with selections. It’s essential to verify the presence of at least one open document before proceeding. Here’s how to achieve that:

if (app.documents.length < 1) {
console.debug('No documents open, aborting');
modeAlertContainer.classList.add('alert__invalid');
mode.textContent = 'Please open a document';

return 'invalid';
}

if (app.selection.length === 0) {
modeAlertContainer.classList.remove('alert__invalid');
mode.textContent = 'Creating a new page (nothing selected)';

return 'new';
}

This change ensures that selections are only addressed within a valid document context. By confirming the existence of an open document beforehand, a more stable plugin environment is established, preempting potential errors and complications.

To me, this underscores a pivotal lesson in InDesign plugin development: a profound comprehension of the platform’s idiosyncrasies is indispensable (I let ChatGPT come up with that sentence 😅).

Testing, Submission, Approval, and Launch

The journey through Testing, Submission, Approval, and Launch was a mix of hurdles and determination. Here’s how it played out:

Things were going pretty well initially. The plugin was running smoothly on my Windows 11 machine. That in itself felt like a significant achievement.

Since I had experience of publishing XD plugins, the submission process itself wasn’t entirely new. I followed the familiar steps, feeling relatively confident.

However, things took an unexpected turn when the review team, who mostly use macOS, ran into a problem. My plugin was causing InDesign to freeze.

Unfortunately, I didn’t have a Mac testing machine at that point, although I had one on the way for another project. The crashes were perplexing, and I couldn’t figure out what was causing them. I reached out to the community for help, but most couldn’t replicate the issue (only Kerri Shotts managed to replicate the behavior once, and once only).

The fog began to lift when Adobe’s engineering team chimed in. They confirmed that the problem wasn’t my plugin’s fault, but was caused by a bug with how InDesign handled the plugin. They were hopeful of fixing it in version 19.0.

Despite this, my itch to release the plugin persisted. I wanted the satisfaction of being the first to officially publish a plugin, now that I had already embarked on that mission 😜.

Luckily, the Mac testing machine arrived, giving me a chance to dig deeper. I discovered a bunch of “potential” issues that cropped up sporadically as I tinkered around. Yet, the exact issue the review team faced remained elusive.

While I couldn’t recreate their specific problem, I decided to make a change to the plugin. I started using setInterval() to check selection instead of relying on selection changes.

This adjustment seemed to work well on my Mac, which makes me hopeful that it has fixed the original issues as well (even though it’s impossible to say for sure since there was no definite way to replicate that behavior, so I might just have had a very lucky 8-hour test run).

I submitted this updated version for review with a bit more confidence. Thankfully, it passed the review process, and on a significant Friday — August 18th, 2023 — the plugin officially launched, becoming available for all InDesign users.

Conclusion

“Every accomplishment starts with the decision to try.” — John F. Kennedy

Looking back, I’m stoked I jumped in and got that first plugin off the ground. Actually seeing it in action is such a win.

But guess what? This is just the start, and there’s a heap more I’m eager to learn and tackle. I’m all in for keeping this project rolling and taking on new ones too.

If you’re keen on diving into plugin making, definitely check out the official docs at https://developer.adobe.com/indesign/uxp/. Oh, and stay tuned — I’ve got plans for a hands-on video series on UXP plugin crafting.

Big shout-outs are in order:

  • Ingo Eichel (who’s also my former manager), for forwarding my issues to the Adobe engineering wizards and giving me some awesome guidance.
  • Amanda Huang, Padma Krishnamoorthy, and the whole Office Hours crew for putting up with my bunch of questions.
  • Kerri Shotts (and nowadays also Padma Krishnamoorthy) for a bunch of work to make UXP what it is today.
  • Erin Finnegan who got me into this mess in the first place 😜 — she sent me the initial invitation into the Adobe XD extensibility prerelease program back in 2018.
  • Massive thanks to the cool community folks who shared wisdom on forums and all that jazz.
  • Remember Gregor Fellenz? Met him at a workshop in Mannheim in 2019. I hope we’ll get to meet in person again someday, but until then, I’ll say it again: your resources around InDesign APIs are a lifesaver!

Before we wrap up, here’s the deal: If you’re into plugins and want to see more, check out my plugin on Adobe Exchange. You can also find the code on my GitHub repo.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in Adobe Tech Blog

News, updates, and thoughts related to Adobe, developers, and technology.

Written by Zuri Klaschka (they/them)

Autistic. A nerd, and happy about it. Passionate about developer experiences, diversity acceptance. Involved in way too many side-projects to count.

Write a response