Skip to content

Wrap custom html field labels in error class when showing in field validation messages#3049

Open
AbdiTolesa wants to merge 5 commits intomasterfrom
issue-6392
Open

Wrap custom html field labels in error class when showing in field validation messages#3049
AbdiTolesa wants to merge 5 commits intomasterfrom
issue-6392

Conversation

@AbdiTolesa
Copy link
Copy Markdown
Contributor

@AbdiTolesa AbdiTolesa commented Mar 27, 2026

Fix https://github.com/Strategy11/formidable-pro/issues/6392

Test procedure

  1. Enable AJAX submission in your form
  2. Add a field and set it to be required
  3. For the field label, use html that has a <div> tag in it. Eg. "Enter your answer
    here
    "
  4. Preview the form and try submitting empty values
  5. Observe that there are validation errors printed
  6. Submit again (before reloading the page and clearing the previous errors)
  7. Confirm that the errors are not duplicated

Summary by CodeRabbit

  • Bug Fixes
    • Improved error message rendering and consistency for form fields: plain-text errors are now reliably wrapped with error markup and inserted uniformly.
    • Preserved and normalized existing HTML-formatted error content by adding the error class when needed and ensuring consistent insertion and optional alert role for accessibility.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

Adds a new helper getErrorHtml(errorMessage, id) in js/formidable.js to centralize and normalize generation of field error HTML. The helper applies role="alert" when frm_js.include_alert_role is truthy, wraps plain-text messages in a <div class="frm_error" ...> or, if the message already starts with "<div", parses it into a temporary DOM node, adds the frm_error class to the first child, and returns the resulting HTML; insertion flow remains unchanged.

Changes

Cohort / File(s) Summary
Error rendering helper
js/formidable.js
Added getErrorHtml(errorMessage, id); replaced inline error HTML construction in addFieldError to call the helper; helper conditionally adds role="alert" (based on frm_js.include_alert_role), wraps non-<div messages in <div class="frm_error" id="...">, and normalizes existing <div> markup by parsing into a temp div and adding the frm_error class before returning innerHTML. DOM insertion (container.insertAdjacentHTML('beforeend', ...)) and aria updates are preserved.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hop through markup, tidy and spry,
Wrap errors in classes, give alerts a try,
A temp div and whiskers make HTML neat,
Messages aligned with a rhythmic beat,
Hooray — forms that chatter politely and shy!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: wrapping custom HTML field labels in error class for field validation messages, which aligns with the code changes that add error class wrapping logic.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6392

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@deepsource-io
Copy link
Copy Markdown

deepsource-io bot commented Mar 27, 2026

DeepSource Code Review

We reviewed changes in 2d8b30e...a1568a9 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
PHP Mar 27, 2026 6:36p.m. Review ↗
JavaScript Mar 27, 2026 6:36p.m. Review ↗

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@js/formidable.js`:
- Around line 1158-1162: The current code creates a temporary container
(tempDiv) and adds the frm_error class to that container but then uses
tempDiv.innerHTML, which returns only children and drops the wrapper and its
attributes; instead, parse the errorMessage into tempDiv, get the parsed node
(e.g., tempDiv.firstElementChild or firstChild), add the frm_error class (and
preserve any id) to that parsed node, and then set errorHtml from the parsed
node's outerHTML so the wrapper, class and id are preserved; reference tempDiv,
errorMessage, errorHtml and the parsed node (firstElementChild) when making the
change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: db707e86-b21a-4e3c-a630-1824cb7b2997

📥 Commits

Reviewing files that changed from the base of the PR and between 2d8b30e and 135b0b2.

📒 Files selected for processing (1)
  • js/formidable.js

js/formidable.js Outdated
Comment on lines +1158 to +1162
if ( errorMessage.startsWith( '<div' ) ) {
const tempDiv = document.createElement( 'div' );
tempDiv.innerHTML = errorMessage;
tempDiv.classList.add( 'frm_error' );
errorHtml = tempDiv.innerHTML;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Does HTMLElement.innerHTML include the element itself or only its descendants? Please cite MDN or equivalent documentation and give a short example.

💡 Result:

HTMLElement.innerHTML includes only the element's descendants, not the element itself. It returns the HTML serialization of the nested child DOM elements within the element. From MDN: "Getting the property returns a string containing the HTML serialization of the element's descendants." [Result 1] Example:

My name is Joe

const myElement = document.querySelector("#example"); console.log(myElement.innerHTML); // "

My name is Joe

" (no outer
) Use outerHTML to include the element itself.

Citations:


🏁 Script executed:

# Check the exact code at lines 1158-1162 and surrounding context
sed -n '1150,1170p' js/formidable.js

Repository: Strategy11/formidable-forms

Length of output: 866


Mutate the parsed error node, not the temporary container.

On lines 1159–1162, adding the frm_error class to tempDiv then reading tempDiv.innerHTML loses the class—innerHTML returns only the element's descendants, not the element itself. This path inserts the original errorMessage without the .frm_error wrapper or id attribute, breaking the PR objective and downstream selectors that depend on those attributes (e.g., removeFieldError, aria-describedby).

🐛 Proposed fix
 			if ( jsErrors[ key ].includes( '<div' ) ) {
 				if ( errorMessage.startsWith( '<div' ) ) {
 					const tempDiv = document.createElement( 'div' );
 					tempDiv.innerHTML = errorMessage;
-					tempDiv.classList.add( 'frm_error' );
-					errorHtml = tempDiv.innerHTML;
+					const existingWrapper = tempDiv.firstElementChild;
+					if ( existingWrapper && existingWrapper.tagName === 'DIV' ) {
+						existingWrapper.classList.add( 'frm_error' );
+						existingWrapper.id = id;
+						if ( frm_js.include_alert_role ) {
+							existingWrapper.setAttribute( 'role', 'alert' );
+						}
+						errorHtml = tempDiv.innerHTML;
+					} else {
+						errorHtml = wrapInErrorClass( errorMessage );
+					}
 				} else {
 					errorHtml = wrapInErrorClass( errorMessage );
 				}
 			} else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/formidable.js` around lines 1158 - 1162, The current code creates a
temporary container (tempDiv) and adds the frm_error class to that container but
then uses tempDiv.innerHTML, which returns only children and drops the wrapper
and its attributes; instead, parse the errorMessage into tempDiv, get the parsed
node (e.g., tempDiv.firstElementChild or firstChild), add the frm_error class
(and preserve any id) to that parsed node, and then set errorHtml from the
parsed node's outerHTML so the wrapper, class and id are preserved; reference
tempDiv, errorMessage, errorHtml and the parsed node (firstElementChild) when
making the change.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
js/formidable.js (1)

1147-1155: ⚠️ Potential issue | 🟠 Major

Custom <div> errors still miss id/role, so aria-describedby can point to a non-existent node.

Line 1153 only adds frm_error on the parsed node. In this branch, the generated element still doesn’t receive the id from addFieldError (and ignores alert role), which breaks the accessibility linkage/cleanup path.

🐛 Proposed fix
 function getErrorHtml( errorMessage, id ) {
 	const roleString = frm_js.include_alert_role ? 'role="alert"' : '';

 	if ( ! errorMessage.startsWith( '<div' ) ) {
 		return `<div class="frm_error" ${ roleString } id="${ id }">${ errorMessage }</div>`;
 	}

 	const tempDiv = document.createElement( 'div' );
 	tempDiv.innerHTML = errorMessage;
-	tempDiv.firstChild.classList.add( 'frm_error' );
+	const existingWrapper = tempDiv.firstElementChild;
+	if ( existingWrapper ) {
+		existingWrapper.classList.add( 'frm_error' );
+		existingWrapper.id = id;
+		if ( frm_js.include_alert_role ) {
+			existingWrapper.setAttribute( 'role', 'alert' );
+		}
+	}

 	return tempDiv.innerHTML;
 }
#!/bin/bash
# Verify current helper behavior around parsed custom HTML error markup.
sed -n '1140,1195p' js/formidable.js

# Confirm parsed-div branch currently mutates firstChild and does not set id/role.
rg -n "getErrorHtml|startsWith\\( '<div' \\)|firstChild\\.classList|existingWrapper|setAttribute\\( 'role'|\\.id\\s*=\\s*id" js/formidable.js

# Verify aria-describedby and cleanup depend on error element id.
rg -n "aria-describedby|getErrorElementId|errorMessage\\.id|removeFieldError" js/formidable.js
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@js/formidable.js` around lines 1147 - 1155, The parsed-HTML branch fails to
apply the id and role attributes that addFieldError expects, breaking
aria-describedby and cleanup; in the function that builds error markup (the
branch that creates tempDiv and uses tempDiv.firstChild), after adding the
frm_error class to tempDiv.firstChild also set its id to the same id value and
apply the roleString (or setAttribute('role', ...)) so the parsed node gets the
same id/role as the non-parsed branch; update getErrorHtml/addFieldError related
logic to ensure tempDiv.firstChild receives id and roleString before returning
tempDiv.innerHTML.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@js/formidable.js`:
- Around line 1147-1155: The parsed-HTML branch fails to apply the id and role
attributes that addFieldError expects, breaking aria-describedby and cleanup; in
the function that builds error markup (the branch that creates tempDiv and uses
tempDiv.firstChild), after adding the frm_error class to tempDiv.firstChild also
set its id to the same id value and apply the roleString (or
setAttribute('role', ...)) so the parsed node gets the same id/role as the
non-parsed branch; update getErrorHtml/addFieldError related logic to ensure
tempDiv.firstChild receives id and roleString before returning
tempDiv.innerHTML.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 22574bc4-b215-4e7a-97ae-fbfa07460255

📥 Commits

Reviewing files that changed from the base of the PR and between f69f6b1 and f840fe9.

📒 Files selected for processing (1)
  • js/formidable.js

@AbdiTolesa AbdiTolesa changed the title Wrap custom html field labels in error class when not Wrap custom html field labels in error class when showing in field validation messages Mar 27, 2026
@AbdiTolesa AbdiTolesa requested a review from lauramekaj1 March 27, 2026 19:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant