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
- Replace `class` with `classes: { 'a b': true }` style objects so maquette can diff them.
- Keep the static class string constant and encode all conditional classes in `classes`.
- 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
- Treat `class` as immutable per node; put all toggles in `classes`.
- Keep the static class string identical across renders of the same node.
- Code review list/conditional rendering for class mutations.
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
- Provide a transitions object to the projectionOptions to do
- Style values must be strings
- Property "className" is not supported, use "class".
- "class" property may not be updated. Use the "classes" prope
- Functions may not be updated on subsequent renders (property
AI-assisted analysis of HelloZeroNet/ZeroNet@454c0b2e7e (2026-09-02).
Data as JSON: /api/errors/11bc1f609d654a12.
Report an issue: GitHub.