No Code Attached Yet bug
avatar hans2103
hans2103
8 Sep 2026

What happened?

Summary

Joomla's core client-side form validation reads a field's data-validation-text HTML attribute and uses its value verbatim as the "invalid" message:

media/system/js/fields/validate.es6.js, markInvalid():
const message = element.getAttribute('data-validation-text');

It only falls back to a translated string, Joomla.Text._('JLIB_FORM_FIELD_INVALID_VALUE'), when the attribute is absent entirely.

data-validation-text can be set per field directly from form XML, because
FormField::setup() copies every data-* XML attribute into $dataAttributes verbatim:

foreach ($this->element->attributes() as $key => $value) {
    if (str_starts_with($key, 'data-')) {
        $this->dataAttributes[$key] = $value;
    }
}

At no point in this chain (XML attribute → FormField::$dataAttributes → field layout → HTML attribute → validate.es6.js) does the value pass through Text::() / Joomla.Text.(). So an extension or template developer who — reasonably, given how label, description and hint behave elsewhere in form XML — sets data-validation-text="MYEXT_FIELD_INVALID_MESSAGE" will see the raw, untranslated language constant shown to end users as the validation error, in every language.

Steps to reproduce

  1. Add data-validation-text="SOME_LANG_KEY" to any form field in a component's XML (e.g. a calendar or text field), where SOME_LANG_KEY is a defined language string in the extension's language file.
  2. Trigger the field's client-side validation (e.g. a pattern mismatch or a required violation).
  3. Observe: the invalid-feedback text shows the literal string SOME_LANG_KEY, not the translated text.

Expected behavior

Either:

  • Document that data-validation-text must contain literal, pre-resolved text (not a language key), so developers don't assume it behaves like label/description/hint; or
  • Resolve data-validation-text (and similarly end-user-facing data-* attributes) throughText::_() when building dataAttributes, consistent with how label/description/hint are already translated in form XML.

Environment

Verified against the current source on both active branches:

  • 5.4-dev (repository default branch) — build/media_source/system/js/fields/validate.es6.js
  • 6.1-dev (current 6.x branch; 6.2-dev does not exist yet) — same file, identical logic

Same element.getAttribute('data-validation-text') / no Text._() call in both.

Version

5.4

Expected result

No response

Actual result

No response

System Information

No response

Additional Comments

No response

avatar hans2103 hans2103 - open - 8 Sep 2026
avatar joomla-cms-bot joomla-cms-bot - change - 8 Sep 2026
Labels Added: No Code Attached Yet bug
avatar joomla-cms-bot joomla-cms-bot - labeled - 8 Sep 2026
avatar hans2103
hans2103 - comment - 8 Sep 2026

Update — root cause narrowed down further

After tracing this deeper against the actual Joomla 6.1.3 source (not just the JS layer):

FormField::getLayoutData() already exposes $validationtext to every field layout (it's in
libraries/src/Form/FormField.php, populated from the XML validationtext attribute). But
across all 36 files in layouts/joomla/form/field/, only text.php actually turns
$validationtext into the data-validation-text attribute that validate.es6.js reads:

// @TODO add a proper string here!!!
!empty($validationtext) ? 'data-validation-text="' . $this->escape(Text::_($validationtext)) . '"' : '',

checkbox.php documents $validationtext in its docblock but never uses it. Every other field
type — including several that already build their own pattern attribute for HTML5 validation
(tel.php, date.php, datetime.php, email.php, url.php, number.php, ...) — has no
reference to it at all. So calendar is not a special case; it's one of ~34 field types missing
a feature that exists, half-finished, in exactly one layout.

Proposed fix

Rather than duplicating that one line across every layout (and finishing the half-done
checkbox.php reference), move it into FormField::renderDataAttributes(), which already
builds $dataAttribute and is echoed by essentially every field layout:

public function renderDataAttributes()
{
    $dataAttribute  = '';
    $dataAttributes = $this->getDataAttributes();

    if (!empty($this->validationtext) && !isset($dataAttributes['data-validation-text'])) {
        $dataAttributes['data-validation-text'] = Text::_($this->validationtext);
    }

    if (!empty($dataAttributes)) {
        foreach ($dataAttributes as $key => $attrValue) {
            $dataAttribute .= ' ' . $key . '="' . htmlspecialchars($attrValue, ENT_COMPAT, 'UTF-8') . '"';
        }
    }

    return $dataAttribute;
}

This makes validationtext work for every field type in one place, with consistent escaping
(current text.php escapes via $this->escape(); ArrayHelper::toString(), used by several
other layouts such as calendar.php, does not escape at all — centralizing this avoids that
inconsistency too). text.php's own line becomes redundant and can be removed, which also
resolves the @TODO add a proper string here!!! left on it.

Happy to turn this into a PR if that's useful.

avatar brianteeman
brianteeman - comment - 8 Sep 2026

sounds like a good idea to me

avatar hans2103 hans2103 - change - 8 Sep 2026
Status New ⇒ Closed
Closed_Date 0000-00-00 00:00:00 ⇒ 2026-09-08 11:31:53
Closed_By ⇒ hans2103
avatar hans2103 hans2103 - close - 8 Sep 2026
avatar hans2103
hans2103 - comment - 8 Sep 2026

PR #48417

Add a Comment

Login with GitHub to post a comment