Skip to content

Fix InPlaceEditor not saving when focus moves outside the editor - #2

Open
olitreadwell wants to merge 1 commit into
masterfrom
fix/inplaceeditor-blur-outside-focus
Open

Fix InPlaceEditor not saving when focus moves outside the editor#2
olitreadwell wants to merge 1 commit into
masterfrom
fix/inplaceeditor-blur-outside-focus

Conversation

@olitreadwell

@olitreadwell olitreadwell commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Problem

<InPlaceEditor> stays open and never saves (or cancels) when focus moves to a focusable element outside it, a neighboring button, link, or input reached by Tab or a click.

The blur handler bailed out for any non-null relatedTarget:

if (event.relatedTarget) {
    return;
}

Browsers set relatedTarget to the element receiving focus, so normal Tab navigation and clicks on focusable controls skip the save/cancel logic.

This contradicts the documented behavior: the field should save automatically when the user clicks outside it, and cancelOnBlur should cancel instead.

Reported in marmelab#11303 (reproduced on current master).

Solution

Only skip save/cancel when focus stays inside the editor (for example, on the Save and Cancel buttons, the case the original guard was meant to protect).

When focus leaves the editor, run the normal blur logic: save the value, or cancel it when cancelOnBlur is set.

if (
    event.relatedTarget &&
    event.currentTarget.contains(event.relatedTarget as Node)
) {
    return;
}

event.currentTarget is the editor Box that owns the onBlur handler, so contains() distinguishes focus moving within the editor from focus leaving it.

Focus lost to a non-focusable target (relatedTarget === null) still saves, as before.

How To Test

git fetch https://github.com/olitreadwell/react-admin.git fix/inplaceeditor-blur-outside-focus
git checkout FETCH_HEAD
yarn jest packages/ra-ui-materialui/src/input/InPlaceEditor

Manually (Storybook story WithSiblingControl, added here):

  1. Click the value to enter edit mode.
  2. Change the text.
  3. Press Tab (or click) to move to the neighboring "Next" button.
  4. The edit is saved (or reverted, with cancelOnBlur), and the editor closes.

Additional Checks

  • The PR targets master for a bugfix or a documentation fix, or next for a feature
  • The PR includes unit tests (three cases added: save on outside focus, cancel on outside focus with cancelOnBlur, and stay-open when focus moves to an inner button)
  • The PR includes one or several stories (WithSiblingControl)
  • The documentation is up to date (the fix makes behavior match the existing InPlaceEditor docs; no doc change needed)

Fork-staging note (not part of the change). This PR is opened against my own fork (olitreadwell/react-admin, base master) as a staging copy before any upstream submission.

Verified locally (MUI 5.16, the repo's dev/CI version):

  • Unit tests: PASS: InPlaceEditor.spec.tsx 9/9 (was 6/6; +3). The two new save/cancel tests fail on master before the fix and pass after; verified failing-first.
  • Lint (eslint): PASS on changed files.
  • Prettier: PASS on changed files.
  • Build/typecheck: PASS: lerna run build --scope ra-ui-materialui --include-dependencies exits 0, no TS errors.
  • AI code review (ocr): not run in this environment; manual self-review done instead.

Diff: 3 files, +56 / -2.

One logical change; no unrelated churn (incidental build edits to package.json exports were reverted).

No CLA bot and no DCO sign-off requirement found in this repo.

To promote upstream (unchanged branch maps 1:1):

gh pr create --repo marmelab/react-admin --base master --head olitreadwell:fix/inplaceeditor-blur-outside-focus

Confidence: HIGH.

Fixes a clear, documented behavior gap with a standard focus-containment check; existing tests unaffected.

AI assistance

Drafted with AI assistance. The change was verified before opening, and the diff was reviewed line by line.


PROMOTION NOTE (remove this section before/when opening against upstream):

gh pr create --repo marmelab/react-admin --base master --head olitreadwell:fix/inplaceeditor-blur-outside-focus

Prerequisites: none outstanding (re-verify CLA/DCO/signing before promoting).

The blur handler returned for any non-null relatedTarget. Browsers set
relatedTarget to the element receiving focus, so tabbing or clicking to a
neighboring focusable control (button, link, input) skipped the save/cancel
logic and left the editor open.

Only skip save/cancel when focus stays inside the editor (for example, on
the Save and Cancel buttons). When focus leaves the editor, save the value,
or cancel it when cancelOnBlur is set.

Closes marmelab#11303
@olitreadwell
olitreadwell force-pushed the fix/inplaceeditor-blur-outside-focus branch from 6e24df6 to 6cca925 Compare August 12, 2026 04:19
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.

1 participant