Skip to content

fix(form): route Ctrl+Enter through onSubmit and stop double-firing on_change#8918

Draft
Mystery01092000 wants to merge 2 commits intomarimo-team:mainfrom
Mystery01092000:fix/form-submit-inconsistencies-8324
Draft

fix(form): route Ctrl+Enter through onSubmit and stop double-firing on_change#8918
Mystery01092000 wants to merge 2 commits intomarimo-team:mainfrom
Mystery01092000:fix/form-submit-inconsistencies-8324

Conversation

@Mystery01092000
Copy link
Copy Markdown

@Mystery01092000 Mystery01092000 commented Mar 29, 2026

Summary

Fixes three related submit-inconsistency bugs in mo.ui.form reported in #8324.

Bug 1 — Ctrl+Enter bypassed onSubmit

FormPlugin.tsx called setValue(newValue) directly in the onKeyDown handler, skipping the <form>'s onSubmit. This meant shouldValidate and clearOnSubmit were silently ignored when using the keyboard shortcut.

Fix: Replace setValue(newValue) with formDiv.current?.requestSubmit(), which routes the keyboard shortcut through the same onSubmit path as the button click.

Bug 2 — Shift+Enter bypassed the form wrapper

OnBlurredInput's onKeyDown in input.tsx fired setValue on any Enter keypress with no modifier check. Shift+Enter inside a wrapped text input would commit the input value directly, completely bypassing the form's buffering layer.

Fix: Add a shiftKey guard — only plain Enter (no Shift) commits the value.

Bug 3 — Wrapped element's on_change fired twice per submission

form._convert_value() called element._update(value), which always triggers the element's _on_change callback. This caused the wrapped element's on_change to fire unexpectedly during form submission (in addition to the form's own on_change).

Fix: Add UIElement._update_value() — identical to _update() but without the _on_change call. form._convert_value() now calls _update_value() so the wrapped element's on_change only fires when the element itself is interacted with, not when the form extracts its submitted value.

Files changed

File Change
frontend/src/plugins/impl/FormPlugin.tsx requestSubmit() instead of direct setValue() in onKeyDown
frontend/src/components/ui/input.tsx shiftKey guard in OnBlurredInput.onKeyDown
marimo/_plugins/ui/_core/ui_element.py New _update_value() method (silent update, no callback)
marimo/_plugins/ui/_impl/input.py form._convert_value uses _update_value not _update
frontend/src/plugins/impl/__tests__/FormPlugin.test.tsx New test file covering all three fixes
tests/_plugins/ui/_impl/test_input.py Three new regression tests for the Python-side fix

Test plan

  • Ctrl+Enter triggers validation when shouldValidate=True
  • Ctrl+Enter clears inputs when clearOnSubmit=True
  • Shift+Enter inside a text input does not submit the form
  • Submit button calls setValue exactly once
  • Wrapped element's on_change does not fire on form submission
  • Form's on_change fires exactly once per submission
  • _update_value() updates value without triggering on_change

Note: Please let me know if any adjustments are needed to match the project's style or conventions. I'm happy to iterate.

I have read the CLA Document and I hereby sign the CLA

@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Mar 29, 2026 5:11pm

Request Review

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 29, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@Mystery01092000
Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

…n_change

Three related bugs in mo.ui.form are fixed:

1. Ctrl+Enter / Cmd+Enter now routes through the <form>'s onSubmit handler
   via requestSubmit() instead of calling setValue() directly. This ensures
   that shouldValidate and clearOnSubmit behave consistently regardless of
   whether the user clicks the button or uses the keyboard shortcut.

2. Shift+Enter inside an OnBlurredInput no longer bypasses the form wrapper.
   A shiftKey guard is added to the onKeyDown handler so that Shift+Enter
   cannot inadvertently commit the input value and skip the form buffer.

3. The wrapped element's on_change callback no longer fires during form
   submission. form._convert_value() previously called element._update(),
   which always triggered on_change. A new _update_value() method on
   UIElement updates the stored value without invoking the callback;
   form._convert_value() now calls that instead, so on_change fires exactly
   once (on the form itself) per submission.

Fixes marimo-team#8324
@Mystery01092000 Mystery01092000 force-pushed the fix/form-submit-inconsistencies-8324 branch from d7f3a4a to 4a844ca Compare March 29, 2026 17:08
@Mystery01092000
Copy link
Copy Markdown
Author

recheck

Copy link
Copy Markdown
Collaborator

@manzt manzt left a comment

Choose a reason for hiding this comment

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

I pulled this down and tested locally but wasn't able to verify that Bug 3 (the double-fire) is fixed. Wrapping a mo.ui.text(on_change=...) in a form and submitting still fires the element's on_change.

Have you verified these change yourself? Could you share a screen recording or a minimal repro snippet showing the correct behavior?

@mscolnick
Copy link
Copy Markdown
Contributor

Going to move to draft while it needs changes.

@mscolnick mscolnick marked this pull request as draft April 1, 2026 18:12
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.

3 participants