From 5c704c3d87c2f06197214cc3115ddd7a56aa9e2c Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Fri, 20 Feb 2026 23:14:48 +0530 Subject: [PATCH 1/2] fix: has-error respects both invalid and mandatory previously set_invalid would remove (if there was no invalid entry) has-error class which were set by set_mandatory fixes #35789 --- frappe/public/js/frappe/form/controls/base_input.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frappe/public/js/frappe/form/controls/base_input.js b/frappe/public/js/frappe/form/controls/base_input.js index 745ab5f620..db335365c0 100644 --- a/frappe/public/js/frappe/form/controls/base_input.js +++ b/frappe/public/js/frappe/form/controls/base_input.js @@ -277,7 +277,9 @@ frappe.ui.form.ControlInput = class ControlInput extends frappe.ui.form.Control // set has-error if dialog primary button is clicked if (this.layout && this.layout.is_dialog && !this.layout.primary_action_fulfilled) return; - this.$wrapper.toggleClass("has-error", Boolean(this.df.reqd && is_null(value))); + const is_invalid = this.$wrapper.hasClass("has-error-invalid"); + this.$wrapper.toggleClass("has-error-mandatory", Boolean(this.df.reqd && is_null(value))); + this.$wrapper.toggleClass("has-error", is_invalid || Boolean(this.df.reqd && is_null(value))); } set_invalid() { let invalid = !!this.df.invalid; @@ -286,7 +288,9 @@ frappe.ui.form.ControlInput = class ControlInput extends frappe.ui.form.Control this.$input?.toggleClass("invalid", invalid); this.grid_row.columns[this.df.fieldname].is_invalid = invalid; } else { - this.$wrapper.toggleClass("has-error", invalid); + const is_mandatory_and_empty = this.$wrapper.hasClass("has-error-mandatory"); + this.$wrapper.toggleClass("has-error-invalid", invalid); + this.$wrapper.toggleClass("has-error", is_mandatory_and_empty || invalid); } } set_required() { From 3a2fe448e8ab0f57ee1f13de0cf871374d877530 Mon Sep 17 00:00:00 2001 From: "stravo1@mac" Date: Fri, 20 Feb 2026 23:30:35 +0530 Subject: [PATCH 2/2] fix: formatting for base_input.js --- frappe/public/js/frappe/form/controls/base_input.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frappe/public/js/frappe/form/controls/base_input.js b/frappe/public/js/frappe/form/controls/base_input.js index db335365c0..8e78c6cab7 100644 --- a/frappe/public/js/frappe/form/controls/base_input.js +++ b/frappe/public/js/frappe/form/controls/base_input.js @@ -279,7 +279,10 @@ frappe.ui.form.ControlInput = class ControlInput extends frappe.ui.form.Control const is_invalid = this.$wrapper.hasClass("has-error-invalid"); this.$wrapper.toggleClass("has-error-mandatory", Boolean(this.df.reqd && is_null(value))); - this.$wrapper.toggleClass("has-error", is_invalid || Boolean(this.df.reqd && is_null(value))); + this.$wrapper.toggleClass( + "has-error", + is_invalid || Boolean(this.df.reqd && is_null(value)) + ); } set_invalid() { let invalid = !!this.df.invalid;