Skip to content
Case Studies

Small things at scale: Layers panel performance

  • CSS
  • DOM APIs
  • JavaScript
  • Chrome DevTools
group selection - team benchmark
733 → 429 ms
nested-input selection - team benchmark
864 → 586 ms
Conceptual illustration of rendering work accumulating across layers during a drag. It is not a benchmark trace.

Context

UXPin is a design tool for interactive prototypes. Its Layers panel shows the tree of elements in a design. People use it to reorder elements by dragging, scroll through the document, and work while changes from collaborators arrive.

Challenge

The panel had to keep up with large designs while the canvas updated alongside it. JavaScript changes could alter the work the browser had to do with the DOM and CSS. We needed to account for both.

Approach

Another developer took the JavaScript improvements, including state management and update batching, and shipped those first. I followed with the HTML and CSS work and helped with the React UI. We shared constraints around the DOM structure as we went.

I started in Chrome DevTools, with the DOM React had actually rendered. Reading the component code told me how we’d organized the interface. Inspecting the result told me what the browser had to process. A small piece of markup repeated throughout the tree could matter more than its place in the source suggested.

The loop was repetitive. Make a change, measure it in DevTools, then look at what moved. I used MDN and W3C documentation to understand the browser’s work behind the CSS properties I was changing.

I reduced DOM elements and unnecessary rendering tiles, and looked for CSS properties that were cheaper to compute. Pseudo-elements were among the details I investigated. The useful question was how much work each choice added across the whole tree during an interaction, rather than whether it looked cheap on one item.

There was no single breakthrough in my part of the rebuild. It took repeated changes and measurements to work through the rendering costs. The JavaScript and DOM/CSS split gave each of us a place to focus, but it wasn’t a clean boundary in the browser: the JavaScript produced and updated the structure I was optimizing. Sharing those constraints was part of the work, not something we could leave until both parts were finished.

Outcome

UXPin published a comparison of the rebuild, including these selection times on the canvas:

InteractionBeforeAfter
Select a group directly on the canvas733 ms429 ms
Select a nested input864 ms586 ms

These measurements cover the team’s rebuild, including the JavaScript improvements and my HTML, CSS, and React UI work. They don’t isolate the effect of my changes or measure frame times.

The comparison used manual Chrome DevTools measurements with 774 visible, unnested layers and 1,482 canvas elements. UXPin didn’t report the hardware, exact browser version, or number of runs. That limits how closely someone else can reproduce the comparison.

Reflection

I came away more careful about drawing conclusions from a small example. I want to profile the interface with a large document and the updates it has to handle. That’s where I can judge whether a change is worth keeping.