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
After initial render, maquette forbids changing the `class` string property on updates; static class changes would require patching in ways maquette does not reconcile. Conditional classes must be expressed with the `classes` object, whose boolean entries maquette adds/removes from the DOM classList on each render.
Source
Thrown at plugins/UiConfig/media/js/all.js:378
}
}
}
};
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
- Move conditional classes into `classes`: { classes: { 'is-active': isActive } } and keep `class` constant (or omit it).
- If the base class never changes, keep it in `class` and only vary `classes`.
- Restructure so each distinct class combination is represented by different vnode structure/keys if truly dynamic static classes are needed.
- As a last resort, manage the class directly via a custom afterCreate/afterUpdate handler, but this bypasses the VDOM diff.
Example fix
// before
h('div', { class: isActive ? 'card active' : 'card' })
// after
h('div', { class: 'card', classes: { active: isActive } }) Defensive patterns
Strategy: validation
Validate before calling
function assertClassStable(prevProps, nextProps) {
if (prevProps && nextProps && prevProps.class !== nextProps.class) {
throw new Error('Move conditional classes into the classes object');
}
} Type guard
function classIsConditionalSafe(prev, next) {
return prev == null || next == null || prev.class === next.class;
} Try / catch
try {
projection.update(vnode);
} catch (e) {
if (e.message.indexOf('"class" property may not be updated') !== -1) {
console.error('Use classes: { name: bool } for conditional classes');
}
throw e;
} Prevention
- Keep the `class` property value a constant string; express all variability via `classes`.
- Never build the class attribute from state or template literals inside render.
- Code-review list/dynamic components for class-in-render patterns.
- If class must truly change, re-create the projection instead of updating it.
When it happens
Trigger: A subsequent projection.update(updatedVnode) (or projector render pass) supplies a vnode whose `class` property value differs from the previous render's value.
Common situations: Building dynamic class strings with template literals or conditionals (class: isActive ? 'a' : 'b'); toggling state classes on re-render; porting code that assumed class behaves like other attributes.
Related errors
- Functions may not be updated on subsequent renders (property
- Provide a transitions object to the projectionOptions to do
- Style values must be strings
- Property "className" is not supported, use "class".
- ${parentVNode.vnodeSelector} had a ${childNode.vnodeSelector
AI-assisted analysis of HelloZeroNet/ZeroNet@454c0b2e7e (2026-09-02).
Data as JSON: /api/errors/196902b50f2f4018.
Report an issue: GitHub.