Skip to content

BUGFIX: template-require-iframe-title — flag title={{null|undefined|number}}#2731

Merged
NullVoxPopuli merged 2 commits into
ember-cli:masterfrom
johanrd:fix/iframe-title-value-checks
Apr 25, 2026
Merged

BUGFIX: template-require-iframe-title — flag title={{null|undefined|number}}#2731
NullVoxPopuli merged 2 commits into
ember-cli:masterfrom
johanrd:fix/iframe-title-value-checks

Conversation

@johanrd
Copy link
Copy Markdown
Contributor

@johanrd johanrd commented Apr 21, 2026

Note

This is part of a series where Claude has audited eslint-plugin-ember against jsx-a11y, vuejs-accessibility, angular-eslint, lit-a11y and html-validate, ember-template-lint, and the HTML and WCAG specs.

Summary

  • Premise 1: <iframe> elements require an accessible name so assistive tech can convey their content. The normative source is WCAG SC 4.1.2 Name, Role, Value; Technique H64 is a sufficient technique citing title as one way to provide it.

  • Premise 2: Mustache literal title values don't supply an author-intended name. At runtime Ember either drops the attribute when the bound value is nullish (no accessible name) or stringifies the literal to "null" / "undefined" / "42" (a coerced placeholder). Empty string literals like {{""}} resolve to "" — same effect as title="".

  • Premise 3: Today our rule only rejects title={{false}}. title={{null}}, title={{undefined}}, title={{42}}, title={{""}}, and their title="{{x}}" concat equivalents silently pass.

  • Conclusion: Treat GlimmerBooleanLiteral, GlimmerNullLiteral, GlimmerUndefinedLiteral, GlimmerNumberLiteral, and empty/whitespace GlimmerStringLiteral as invalid title values in both the title={{x}} and title="{{x}}" positions.

Fix: extract isInvalidTitleLiteralPath() for the four non-string literal types and a shared processStaticTitle() helper that handles text-node, mustache-string-literal, and concat-string-literal forms uniformly. Empty / whitespace string literals follow the same emptiness path as text-node title="".

Tests cover each literal type × each syntax form (bare-mustache and concat).

Whitespace-only title — now opt-out via schema option

The rule previously flagged title=" " (whitespace-only static) as a hard error. This is stricter than ACCNAMEACCNAME 1.2 §4.3.2 step 2I (Tooltip) just says "return its value" with no trim (unlike step D AriaLabel, which has an explicit nor, when trimmed of whitespace, is not the empty string check), so a 3-space accessible name is technically assigned. The check remains on by default as an authoring-hygiene guard (useless in practice), but teams that want spec-aligned behavior can opt out via the new allowWhitespaceOnlyTitle: true option. Empty-string title="", the non-string literal cases above, and empty-string-literal mustaches are not affected by this option — they are always flagged as correctness.

Prior art

Peers diverge materially on empty/non-string title handling. Don't assume parity:

Plugin Rule Verified behavior
jsx-a11y iframe-has-title Check is if (title && typeof title === 'string') → bail. Flags title="" (falsy), flags title={42} (not a string), flags title={null} (falsy). Does NOT flag title=" " (truthy string).
vuejs-accessibility iframe-has-title Check is title === null || !["string","object"].includes(typeof title) → flag. Does NOT flag title="" (typeof "string"). Flags :title='2' (number not a string).
lit-a11y iframe-title Existence-only at line 38: !element.attribs.title || element.attribs.title === undefined. Flags title="" (falsy), does NOT flag non-string values (parse5 yields strings only).
@angular-eslint/template No iframe-title equivalent in the rules directory.

… add allowWhitespaceOnlyTitle opt-out

Treat literal AST values that don't produce a meaningful accessible name
as invalid `<iframe title>` values:

- `GlimmerBooleanLiteral` / `GlimmerNullLiteral` / `GlimmerUndefinedLiteral` /
  `GlimmerNumberLiteral` → flagged with a new `invalidTitleLiteral` messageId.
  Coerce-to-string runtime values like "true" / "null" / "42" don't
  describe the frame contents, regardless of framework behavior.
- `GlimmerStringLiteral` resolving to empty / whitespace → flagged as
  `emptyTitle` (resolution shared with the text-node case via a
  `processStaticTitle` helper). Closes a bypass that jsx-a11y already
  catches via `getLiteralPropValue`.

Both literal classes apply to the bare-mustache `title={{x}}` form AND
the single-part concat `title="{{x}}"` form.

Whitespace-only static title (`title="   "`) is now opt-out via a new
`allowWhitespaceOnlyTitle: true` schema option. ACCNAME 1.2 §4.3.2 step
2I (Tooltip) does not whitespace-trim — so a 3-space accessible name is
spec-assigned. The check stays on by default as authoring hygiene; teams
that want strict spec parity can opt out. Empty-string `title=""` and
the non-string-literal cases above are not affected by this option —
they are always flagged as correctness.

Refs:
- WCAG SC 4.1.2: https://www.w3.org/TR/UNDERSTANDING-WCAG20/ensure-compat-rsv.html
- ACCNAME 1.2 §4.3.2: https://www.w3.org/TR/accname-1.2/#computation-steps
@johanrd johanrd force-pushed the fix/iframe-title-value-checks branch from 5dd3c75 to 19e44c4 Compare April 25, 2026 06:15
@johanrd johanrd marked this pull request as ready for review April 25, 2026 06:15

## Configuration

- `allowWhitespaceOnlyTitle` (`boolean`, default `false`): when `true`,
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.

why would we want to allow this?

Copy link
Copy Markdown
Contributor Author

@johanrd johanrd Apr 25, 2026

Choose a reason for hiding this comment

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

Hehe, basically because I (johan) didn't dare to have strict opinions on the behavior. but I feel somewhat silly defending it.

The option exists because the default is stricter than spec — it's an authoring-hygiene guard, not a normative requirement. Two relevant ACCNAME 1.2 steps from https://www.w3.org/TR/accname-1.2/#computation-steps. title=" " technically produces a three-space accessible name — spec-compliant, useless in practice. The option lets teams opt back to what the spec actually requires rather than our stricter default.

I doubt anyone will intentionally write a whitespace-only title. Should probably drop the option entirely and always flag it

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed it now

…tle option

Whitespace-only titles are never intentional and the option added API
surface with no real-world use case. Always flag empty/whitespace title
values as errors.
@johanrd johanrd requested a review from NullVoxPopuli April 25, 2026 15:17
@NullVoxPopuli NullVoxPopuli merged commit e170971 into ember-cli:master Apr 25, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants