Engineering Journal
Schema Editor
Schema Editor

Layer Rename Does Not Persist After the Next Panel Rebuild

2026-06-04

TLDR

Layer name updates that appear to succeed in the UI but revert back to old values on the next canvas rebuild stem from asynchronous race conditions. Attempting to synchronize id and data-layer-name attributes using a MutationObserver fails because MutationObserver callbacks execute as microtasks, firing after the synchronous DOM rebuild pass reads the old attribute value. Updating both attributes synchronously at edit time fixes the persistence bug.
Mutation ApproachExecution TimingRebuild State ReadOutcome
MutationObserver MicrotaskAsynchronous MicrotaskReads old data-layer-name before writeReverts to old name (BUG)
Synchronous Attribute AssignmentSynchronous ExecutionReads updated data-layer-name value100% Persistent Layer Rename

Problem statement: the temporary layer rename glitch

Users double-clicking a layer row to rename an element (e.g., changing "Resistor-1" to "Power Resistor R1") saw the new name render in the layer panel.

However, as soon as any subsequent canvas action occurred (such as dragging a component or adding a shape), the layer panel rebuilt itself and reverted back to the original name.


Technical failure mode: microtask race conditions in MutationObservers

The original implementation attempted to keep element id and data-layer-name attributes in sync via a MutationObserver:

// DEFECTIVE IMPLEMENTATION: Observer callback executes AFTER synchronous rebuild!
function renameElement(el, newName) {
  const obs = new MutationObserver(() => {
    el.setAttribute('data-layer-name', el.id.replace(/-/g, ' '));
    obs.disconnect();
  });
  obs.observe(el, { attributes: true, attributeFilter: ['id'] });

el.id = newName.replace(/\s+/g, '-').toLowerCase(); // ID assignment triggers observer // A canvas rebuild triggered in the same synchronous turn reads 'data-layer-name' // BEFORE the MutationObserver microtask callback executes! }

Because MutationObserver tasks execute asynchronously on the microtask queue, a synchronous canvas rebuild pass running in the same turn reads data-layer-name before the observer updates it, rendering the old attribute value.


The fix: synchronous attribute assignment

Eliminate the MutationObserver and update both attributes synchronously at the moment of user entry:

// REFACTORED: Synchronous attribute assignment
function renameElement(el, newName) {
  const safeId = newName.trim().replace(/\s+/g, '-').toLowerCase();
  
  el.id = safeId;
  el.setAttribute('data-layer-name', newName.trim()); // Synchronous write!

// Instant DOM-derived panel refresh guarantees attribute parity buildLayerPanel(contentRoot, panelContainer); }

Rule of thumb: Never use asynchronous MutationObserver tasks to synchronize two attributes under your direct control. Perform attribute updates synchronously to prevent microtask race conditions during UI rebuilds.
Read this post in the full Engineering Journal →