Skip to content

[BUGFIX] Fix missing value attribute on radio/checkbox inputs bound to empty string #21109

Merged
NullVoxPopuli merged 1 commit intoemberjs:mainfrom
johanrd:fix/19219
Mar 3, 2026
Merged

[BUGFIX] Fix missing value attribute on radio/checkbox inputs bound to empty string #21109
NullVoxPopuli merged 1 commit intoemberjs:mainfrom
johanrd:fix/19219

Conversation

@johanrd
Copy link
Copy Markdown
Contributor

@johanrd johanrd commented Feb 21, 2026

  • Fixes <input type="radio" value={{""}}> not rendering the value attribute
  • Adds regression test

Root cause

Glimmer applies dynamic attributes (value) before static attributes (type) during element construction. The sequence is:

  1. input.value = '' — no-op, '' is already the default for type="text"
  2. input.type = 'radio' — default value changes to "on", browser doesn't retroactively reflect the earlier empty string

This was originally reported as Firefox-only but is now reproducible in Chrome 145+.

Fix

When value is explicitly set to '' on an <input>, also call setAttribute('value', '') in addition to the property setter. This ensures the attribute is present in the DOM regardless of attribute application order. The <textarea> case is excluded since it doesn't use a value attribute.

Closes #19219

Cowritten by Claude

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 21, 2026

Estimated Asset Sizes

Diff

--- main/out.txt	2026-03-03 16:45:40.000000000 +0000
+++ pr/./pr-22633773861/out.txt	2026-03-03 17:02:04.000000000 +0000
@@ -1,7 +1,7 @@
 ╔═══════╤═══════════╤═══════════╗
 ║       │ Min       │ Gzip      ║
 ╟───────┼───────────┼───────────╢
-║ Total │ 351.99 KB │ 203.84 KB ║
+║ Total │ 351.99 KB │ 203.85 KB ║
 ╚═══════╧═══════════╧═══════════╝
 
 ╔══════════════════════╤═══════════╤═══════════╗
@@ -10,25 +10,25 @@
 ║ Total                │ 313.39 KB │ 181.91 KB ║
 ╟──────────────────────┼───────────┼───────────╢
 ║ -internals           │ 36.65 KB  │ 26.22 KB  ║
-║ application          │ 13.23 KB  │ 8.05 KB   ║
+║ application          │ 13.23 KB  │ 8 KB      ║
 ║ array                │ 13.01 KB  │ 7.46 KB   ║
 ║ canary-features      │ 304 B     │ 389 B     ║
-║ component            │ 2.05 KB   │ 1.64 KB   ║
+║ component            │ 2.05 KB   │ 1.65 KB   ║
 ║ controller           │ 1.96 KB   │ 1.41 KB   ║
 ║ debug                │ 11.69 KB  │ 8.12 KB   ║
 ║ deprecated-features  │ 31 B      │ 77 B      ║
 ║ destroyable          │ 561 B     │ 383 B     ║
 ║ enumerable           │ 259 B     │ 387 B     ║
-║ helper               │ 1.08 KB   │ 811 B     ║
+║ helper               │ 1.08 KB   │ 813 B     ║
 ║ instrumentation      │ 2.43 KB   │ 1.79 KB   ║
-║ modifier             │ 1.22 KB   │ 965 B     ║
+║ modifier             │ 1.22 KB   │ 967 B     ║
 ║ object               │ 35.94 KB  │ 22.16 KB  ║
 ║ owner                │ 159 B     │ 178 B     ║
-║ renderer             │ 630 B     │ 487 B     ║
-║ routing              │ 59.3 KB   │ 34.12 KB  ║
+║ renderer             │ 630 B     │ 506 B     ║
+║ routing              │ 59.3 KB   │ 34.13 KB  ║
 ║ runloop              │ 2.36 KB   │ 1.5 KB    ║
 ║ service              │ 1 KB      │ 845 B     ║
-║ template             │ 654 B     │ 541 B     ║
+║ template             │ 654 B     │ 539 B     ║
 ║ template-compilation │ 429 B     │ 366 B     ║
 ║ template-compiler    │ 123.08 KB │ 59.45 KB  ║
 ║ template-factory     │ 370 B     │ 374 B     ║
@@ -47,12 +47,12 @@
 ║ env             │ 38 B     │ 87 B     ║
 ║ global-context  │ 886 B    │ 545 B    ║
 ║ manager         │ 977 B    │ 608 B    ║
-║ node            │ 175 B    │ 260 B    ║
+║ node            │ 175 B    │ 259 B    ║
 ║ opcode-compiler │ 1.11 KB  │ 894 B    ║
 ║ owner           │ 159 B    │ 202 B    ║
 ║ program         │ 252 B    │ 301 B    ║
 ║ reference       │ 548 B    │ 531 B    ║
-║ runtime         │ 10.32 KB │ 5.32 KB  ║
+║ runtime         │ 10.32 KB │ 5.33 KB  ║
 ║ tracking        │ 1.34 KB  │ 1.16 KB  ║
 ║ util            │ 1.94 KB  │ 1.68 KB  ║
 ║ validator       │ 15.75 KB │ 6.96 KB  ║

Details

This PRmain
╔═══════╤═══════════╤═══════════╗
║       │ Min       │ Gzip      ║
╟───────┼───────────┼───────────╢
║ Total │ 351.99 KB │ 203.85 KB ║
╚═══════╧═══════════╧═══════════╝

╔══════════════════════╤═══════════╤═══════════╗
║ @ember/*             │ Min       │ Gzip      ║
╟──────────────────────┼───────────┼───────────╢
║ Total                │ 313.39 KB │ 181.91 KB ║
╟──────────────────────┼───────────┼───────────╢
║ -internals           │ 36.65 KB  │ 26.22 KB  ║
║ application          │ 13.23 KB  │ 8 KB      ║
║ array                │ 13.01 KB  │ 7.46 KB   ║
║ canary-features      │ 304 B     │ 389 B     ║
║ component            │ 2.05 KB   │ 1.65 KB   ║
║ controller           │ 1.96 KB   │ 1.41 KB   ║
║ debug                │ 11.69 KB  │ 8.12 KB   ║
║ deprecated-features  │ 31 B      │ 77 B      ║
║ destroyable          │ 561 B     │ 383 B     ║
║ enumerable           │ 259 B     │ 387 B     ║
║ helper               │ 1.08 KB   │ 813 B     ║
║ instrumentation      │ 2.43 KB   │ 1.79 KB   ║
║ modifier             │ 1.22 KB   │ 967 B     ║
║ object               │ 35.94 KB  │ 22.16 KB  ║
║ owner                │ 159 B     │ 178 B     ║
║ renderer             │ 630 B     │ 506 B     ║
║ routing              │ 59.3 KB   │ 34.13 KB  ║
║ runloop              │ 2.36 KB   │ 1.5 KB    ║
║ service              │ 1 KB      │ 845 B     ║
║ template             │ 654 B     │ 539 B     ║
║ template-compilation │ 429 B     │ 366 B     ║
║ template-compiler    │ 123.08 KB │ 59.45 KB  ║
║ template-factory     │ 370 B     │ 374 B     ║
║ test                 │ 923 B     │ 627 B     ║
║ utils                │ 4.11 KB   │ 3.6 KB    ║
║ version              │ 55 B      │ 131 B     ║
╚══════════════════════╧═══════════╧═══════════╝

╔═════════════════╤══════════╤══════════╗
║ @glimmer/*      │ Min      │ Gzip     ║
╟─────────────────┼──────────┼──────────╢
║ Total           │ 38.6 KB  │ 21.94 KB ║
╟─────────────────┼──────────┼──────────╢
║ destroyable     │ 2.77 KB  │ 1.39 KB  ║
║ encoder         │ 81 B     │ 171 B    ║
║ env             │ 38 B     │ 87 B     ║
║ global-context  │ 886 B    │ 545 B    ║
║ manager         │ 977 B    │ 608 B    ║
║ node            │ 175 B    │ 259 B    ║
║ opcode-compiler │ 1.11 KB  │ 894 B    ║
║ owner           │ 159 B    │ 202 B    ║
║ program         │ 252 B    │ 301 B    ║
║ reference       │ 548 B    │ 531 B    ║
║ runtime         │ 10.32 KB │ 5.33 KB  ║
║ tracking        │ 1.34 KB  │ 1.16 KB  ║
║ util            │ 1.94 KB  │ 1.68 KB  ║
║ validator       │ 15.75 KB │ 6.96 KB  ║
║ vm              │ 495 B    │ 569 B    ║
║ wire-format     │ 1.84 KB  │ 1.35 KB  ║
╚═════════════════╧══════════╧══════════╝
╔═══════╤═══════════╤═══════════╗
║       │ Min       │ Gzip      ║
╟───────┼───────────┼───────────╢
║ Total │ 351.99 KB │ 203.84 KB ║
╚═══════╧═══════════╧═══════════╝

╔══════════════════════╤═══════════╤═══════════╗
║ @ember/*             │ Min       │ Gzip      ║
╟──────────────────────┼───────────┼───────────╢
║ Total                │ 313.39 KB │ 181.91 KB ║
╟──────────────────────┼───────────┼───────────╢
║ -internals           │ 36.65 KB  │ 26.22 KB  ║
║ application          │ 13.23 KB  │ 8.05 KB   ║
║ array                │ 13.01 KB  │ 7.46 KB   ║
║ canary-features      │ 304 B     │ 389 B     ║
║ component            │ 2.05 KB   │ 1.64 KB   ║
║ controller           │ 1.96 KB   │ 1.41 KB   ║
║ debug                │ 11.69 KB  │ 8.12 KB   ║
║ deprecated-features  │ 31 B      │ 77 B      ║
║ destroyable          │ 561 B     │ 383 B     ║
║ enumerable           │ 259 B     │ 387 B     ║
║ helper               │ 1.08 KB   │ 811 B     ║
║ instrumentation      │ 2.43 KB   │ 1.79 KB   ║
║ modifier             │ 1.22 KB   │ 965 B     ║
║ object               │ 35.94 KB  │ 22.16 KB  ║
║ owner                │ 159 B     │ 178 B     ║
║ renderer             │ 630 B     │ 487 B     ║
║ routing              │ 59.3 KB   │ 34.12 KB  ║
║ runloop              │ 2.36 KB   │ 1.5 KB    ║
║ service              │ 1 KB      │ 845 B     ║
║ template             │ 654 B     │ 541 B     ║
║ template-compilation │ 429 B     │ 366 B     ║
║ template-compiler    │ 123.08 KB │ 59.45 KB  ║
║ template-factory     │ 370 B     │ 374 B     ║
║ test                 │ 923 B     │ 627 B     ║
║ utils                │ 4.11 KB   │ 3.6 KB    ║
║ version              │ 55 B      │ 131 B     ║
╚══════════════════════╧═══════════╧═══════════╝

╔═════════════════╤══════════╤══════════╗
║ @glimmer/*      │ Min      │ Gzip     ║
╟─────────────────┼──────────┼──────────╢
║ Total           │ 38.6 KB  │ 21.94 KB ║
╟─────────────────┼──────────┼──────────╢
║ destroyable     │ 2.77 KB  │ 1.39 KB  ║
║ encoder         │ 81 B     │ 171 B    ║
║ env             │ 38 B     │ 87 B     ║
║ global-context  │ 886 B    │ 545 B    ║
║ manager         │ 977 B    │ 608 B    ║
║ node            │ 175 B    │ 260 B    ║
║ opcode-compiler │ 1.11 KB  │ 894 B    ║
║ owner           │ 159 B    │ 202 B    ║
║ program         │ 252 B    │ 301 B    ║
║ reference       │ 548 B    │ 531 B    ║
║ runtime         │ 10.32 KB │ 5.32 KB  ║
║ tracking        │ 1.34 KB  │ 1.16 KB  ║
║ util            │ 1.94 KB  │ 1.68 KB  ║
║ validator       │ 15.75 KB │ 6.96 KB  ║
║ vm              │ 495 B    │ 569 B    ║
║ wire-format     │ 1.84 KB  │ 1.35 KB  ║
╚═════════════════╧══════════╧══════════╝

this.render(`<input type="radio" value={{this.value}}>`, { value: '' });

this.assert.strictEqual(
this.inputElement().getAttribute('value'),
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.

What did this return before the fix?

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.

  • actual: null
  • expected: "" (empty string)
  • message: "value attribute is present and empty on initial render"

@NullVoxPopuli NullVoxPopuli merged commit bcc24cf into emberjs:main Mar 3, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug?] input[type=radio] value attr is not rendered if binded to empty string (FF only)

2 participants