HelloZeroNet/ZeroNet · error · Error

"class" property may not be updated. Use the "classes" prope

Error message

"class" property may not be updated. Use the "classes" property for conditional css classes.

What it means

maquette does not support changing the `class` string property between renders of the same node; updateProperties throws if previousValue !== propValue. Developers must use the `classes` object property, whose boolean keys maquette diffs by toggling DOM classList entries.

Source

Thrown at plugins/UiConfig/media/js/lib/maquette.js:189

                }
            }
        }
    };
    var updateProperties = function (domNode, previousProperties, properties, projectionOptions) {
        if (!properties) {
            return;
        }
        var propertiesUpdated = false;
        var propNames = Object.keys(properties);
        var propCount = propNames.length;
        for (var i = 0; i < propCount; i++) {
            var propName = propNames[i];
            // assuming that properties will be nullified instead of missing is by design
            var propValue = properties[propName];
            var previousValue = previousProperties[propName];
            if (propName === 'class') {
                if (previousValue !== propValue) {
                    throw new Error('"class" property may not be updated. Use the "classes" property for conditional css classes.');
                }
            } else if (propName === 'classes') {
                var classList = domNode.classList;
                var classNames = Object.keys(propValue);
                var classNameCount = classNames.length;
                for (var j = 0; j < classNameCount; j++) {
                    var className = classNames[j];
                    var on = !!propValue[className];
                    var previousOn = !!previousValue[className];
                    if (on === previousOn) {
                        continue;
                    }
                    propertiesUpdated = true;
                    if (on) {
                        classList.add(className);
                    } else {
                        classList.remove(className);
                    }

View on GitHub (pinned to 454c0b2e7e)

Solutions

  1. Replace `class` with `classes: { 'a b': true }` style objects so maquette can diff them.
  2. Keep the static class string constant and encode all conditional classes in `classes`.
  3. If the class truly must change, give the node a different key so it is recreated instead of updated.

Example fix

// before
h('div', { class: isActive ? 'tab active' : 'tab' })
// after
h('div', { class: 'tab', classes: { active: isActive } })
Defensive patterns

Strategy: type-guard

Validate before calling

function classIsStable(prevProps, nextProps) {
  return prevProps == null || nextProps == null || prevProps.class === nextProps.class;
}

Type guard

function usesConditionalClasses(props) {
  return props == null || typeof props.class !== 'string' || props.classes === undefined || typeof props.classes === 'object';
}

Try / catch

try {
  projection.update(newVNode);
} catch (e) {
  if (/"class" property may not be updated/.test(e.message)) {
    // re-create projection with the new root instead of updating
    recreateProjection(newVNode);
  } else { throw e; }
}

Prevention

When it happens

Trigger: A vnode rendered with h('div', { class: 'a' }) is re-rendered as h('div', { class: 'a b' }) on the same DOM node during updateProperties.

Common situations: Conditionally changing styling on state change, appending modifier classes on toggle, or reusing JSX/other-VDOM code that treats class as freely mutable.

Related errors


AI-assisted analysis of HelloZeroNet/ZeroNet@454c0b2e7e (2026-09-02). Data as JSON: /api/errors/11bc1f609d654a12. Report an issue: GitHub.