Skip to content

fix(InputNumber): keep previous value on unparseable input, emit null when cleared - #6772

Open
61021 wants to merge 2 commits into
nuxt:v4from
61021:fix/input-number-unparseable
Open

61021 wants to merge 2 commits into
nuxt:v4from
61021:fix/input-number-unparseable

Conversation

@61021

@61021 61021 commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

🔗 Linked issue

Resolves #6743

❓ Type of change

  • 📖 Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • 👌 Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

📚 Description

First, a root-cause correction for the issue title: no NaN is ever emitted. Committing unparseable text like . or - (Enter/blur) makes reka-ui's NumberField emit undefined — the reporter's isNaN(v) check reads true because isNaN(undefined) is true, and undefined poisons downstream arithmetic into NaN. Reka's applyInputValue conflates two situations that deserve different handling: a cleared input and non-empty unparseable text both nuke the model to undefined (and destroy the previous value).

Two commits, separable:

1. fix(InputNumber): keep previous value when committing unparseable input — what the reporter asked for ("maybe just revert to the previous value instead?"), matching react-spectrum's behavior. All model updates now flow through onUpdate() — previously the auto-forwarded update:modelValue handler bypassed it entirely in non-.optional mode (and double-emitted in .optional mode). When the committed value is undefined but the input still contains text, the update is dropped; since NumberFieldRoot runs controlled, it restores the last formatted value on its own. Verified in the added test: . + Enter on a model of 5 → no emit, input text back to 5.

2. fix(InputNumber): emit null when cleared to match the declared model type — the typing-soundness half reported by @danekslama in the issue comments: the emit type is number | null (undefined only with the .optional modifier), but clearing leaked undefined at runtime regardless. Clearing now emits null, or undefined with .optional (unchanged). This one is mildly behavior-visible for consumers who relied on the untyped undefined — happy to drop this commit if you'd rather keep it wrapper-compatible, the first commit stands alone.

Tests cover all three paths (unparseable revert / clear → null / clear + .optionalundefined); existing suites and snapshots unchanged (110 tests green, vue-tsc clean).

Upstream note: the revert-on-unparseable behavior arguably belongs in reka-ui's applyInputValue eventually, but the wrapper can't wait on that and needs the null convention regardless — no reka-ui issue exists for it yet, I can file one.

📝 Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

@61021
61021 requested a review from benjamincanac as a code owner July 24, 2026 16:41
@github-actions github-actions Bot added the v4 #4488 label Jul 24, 2026
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 531d0541-a9a2-4aaa-bfac-21d9744ec4ed

📥 Commits

Reviewing files that changed from the base of the PR and between de69424 and 6c66f9f.

📒 Files selected for processing (2)
  • src/runtime/components/InputNumber.vue
  • test/components/InputNumber.spec.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

InputNumber now suppresses direct update:modelValue forwarding from the underlying number field. Its update handler distinguishes unparseable text from cleared input, preserving the previous value for invalid text and converting cleared input to null or undefined based on the optional modifier. Tests cover invalid input and both clearing behaviors.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 6c66f

Invalid input preserves the existing value, while clearing emits the contractually correct null or undefined value. The change is mergeable.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the InputNumber fixes, expected behavior for unparseable and cleared input, and the added tests.
Title check ✅ Passed The title clearly summarizes the main changes: preserving the previous value for unparseable input and emitting null when input is cleared.
Linked Issues check ✅ Passed Issue #6743 requires InputNumber to avoid an invalid result when the user commits unparseable text such as . or -. src/runtime/components/InputNumber.vue now returns from onUpdate() when Reka …
Out of Scope Changes check ✅ Passed The changes are limited to InputNumber update handling and tests for the linked input states. The clearing normalization supports the required distinction between unparseable text and cleared input.…
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

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.

@pkg-pr-new

pkg-pr-new Bot commented Jul 24, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/@nuxt/ui@6772

commit: 6c66f9f

@61021

61021 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Friendly bump — CI green. This aligns InputNumber with native number-input behavior (keep the previous value on unparseable input, emit null when cleared). Happy to adjust the emit contract if you'd prefer different semantics.

@61021
61021 force-pushed the fix/input-number-unparseable branch from ac3c741 to de69424 Compare August 6, 2026 07:22
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@codspeed

codspeed Bot commented Aug 6, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing 61021:fix/input-number-unparseable (6c66f9f) with v4 (27a3ef7)

Open in CodSpeed

61021 and others added 2 commits September 18, 2026 15:08
reka reports unparseable text ("." / "-") and a cleared input as the same
undefined. Committing "." on a field holding 5 emitted undefined while the
input restored its own display to 5, so the parent lost the value and the
UI disagreed with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…type

Clearing the field emitted undefined while the model type declares
number | null, so a cleared input did not round-trip through a
null-typed model. The optional modifier still emits undefined.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@61021
61021 force-pushed the fix/input-number-unparseable branch from de69424 to 6c66f9f Compare September 18, 2026 12:11
@61021

61021 commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on v4. The conflict was #6859, which stopped forwarding update:modelValue from the root: the emit filter this PR needed is gone, so the fix is now 7 lines inside onUpdate.

The bug is still there on today's v4. With modelValue 5, committing "." emits undefined while the input restores its own display to 5, so the parent loses the value and the field disagrees with it. Clearing emits undefined where the model type says number | null.

@benjamincanac the second commit is the behavioral half and it is split out on purpose, so it can be dropped on its own. pnpm lint and vue-tsc are clean, 118 InputNumber tests pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

InputNumber can return NaN

1 participant