Skip to content

fix: keep keyboard focus in the native property prompts on Obsidian 1.13+ - #218

Merged
chhoumann merged 4 commits into
masterfrom
fix/native-prompt-initial-focus
Oct 24, 2026
Merged

chhoumann merged 4 commits into
masterfrom
fix/native-prompt-initial-focus

Conversation

@chhoumann

@chhoumann chhoumann commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

On Obsidian 1.13+, MetaEdit's native property prompts lost keyboard focus the moment they opened. A user who opened Edit Meta on a property, or "New YAML property", and started typing typed into nothing. Focus had landed on the type pill. In the edit prompt, Obsidian's value autocomplete stayed open and swallowed keys such as Enter on a list pill until Escape.

Cause

Obsidian 1.13's Modal.open() runs onOpen(), which focuses our value editor or key input. When the private hasInitialInputFocus flag is on, it then focuses the modal's first focusable element. In both prompts that is the type pill. A stack trace on focus() showed both calls, in that order. The autocomplete popover opened by the first focus is left orphaned, and its keymap scope catches Enter in the capture phase.

GenericPrompt and AutoPropertyValueModal are unaffected, since their input is their first focusable element.

Fix

NativePropertyPrompt and FluidPropertyCreatePrompt declare hasInitialInputFocus = false as a class field. This is the same opt-out Obsidian's own focus-managing modals use. It is undocumented, so the new E2E tests are what fail if a future Obsidian renames it. Those tests run locally only, because CI has no Obsidian.

Tests

  • test(e2e): pin initial focus ... adds two live tests:
    • The edit prompt opens focused on the value editor and edits a pill in place. The test writes a sibling note that shares the key, so the autocomplete always renders.
    • The create modal opens with focus in the key input.
    • Both fail without the fix.
  • test(e2e): scope the legacy-suggester probe ... narrows a probe in multi-value.test.ts. It matched any .suggestion-item, including Obsidian's own property-value autocomplete, so two tests failed on master. It now matches SuggestModal rows (.prompt-results .suggestion-item), and the existing legacy-flow tests prove it still sees a real GenericSuggester.
  • There is no unit test. The jsdom-free stub's Modal.open() has no focus pass, so a unit test could only assert that the flag is set.

Verification

Obsidian 1.13.7 on Linux, isolated obsidian-e2e vault.

No settings, storage or API change.


Note

Medium Risk
The fix depends on Obsidian’s private Modal focus flag; a rename or removal could regress focus behavior without compile-time signal.

Overview
Fixes keyboard focus in MetaEdit’s native property modals on Obsidian 1.13+, where Modal.open() was refocusing the type pill after onOpen() had already focused the intended field.

FluidPropertyCreatePrompt and NativePropertyPrompt now set Obsidian’s undocumented hasInitialInputFocus = false so focus stays on the key input (create) or value editor (edit) instead of jumping to the first focusable control. That avoids typing into nothing and prevents an orphaned value autocomplete popover from stealing Enter on list pills.

E2E: New tests assert initial focus on the key input and on the multi-value editor (with a sibling note to force autocomplete). multi-value.test.ts narrows the legacy GenericSuggester probe to .prompt-results .suggestion-item so native property autocomplete rows are not mistaken for the legacy suggester.

Reviewed by Cursor Bugbot for commit f561859. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix keyboard focus loss in native property prompts on Obsidian 1.13+

  • Adds the modal focus opt-out state to FluidPropertyCreatePrompt and NativePropertyPrompt, so the modal lifecycle no longer moves focus from the key input / value editor to the type pill after opening
  • Adds E2E regression tests: one for fluid create focus in fluid-create.test.ts, and one covering focus plus in-place pill editing in native-properties.test.ts
  • Scopes the legacy suggester selector to .prompt-results in multi-value.test.ts so it no longer matches native property autocomplete rows

Macroscope summarized f561859.

Obsidian 1.13's Modal.open() focuses the modal's first focusable element
after onOpen(). In both native prompts that element is the type pill, so
focus never reaches the value editor (edit prompt) or the key input (create
modal). In the edit prompt, the value autocomplete popover the editor opened
is left orphaned and its keymap scope swallows Enter on a pill.

Both tests fail on the current plugin.
Obsidian 1.13's Modal.open() runs onOpen() and then focuses the modal's
first focusable element unless hasInitialInputFocus is false. Both native
prompts render the type pill first, so focus left the value editor (edit
prompt) and the key input (create modal) the moment they opened. Typing
went nowhere, and in the edit prompt the value autocomplete popover the
editor had opened stayed open with its keymap scope, swallowing Enter.

Opt both modals out so their own onOpen() focus stands, as Obsidian's own
focus-managing modals do.
driveNativeEdit flagged any `.suggestion-item` as the legacy
GenericSuggester. Obsidian's own property-value autocomplete renders the
same class in a body-level `.suggestion-container` whenever a native editor
has focus, so the scalar tests failed on Obsidian's popover, not on MetaEdit
UI. Match only rows inside a SuggestModal's `.prompt-results`, and have the
legacy driver wait on the same selector so its passing tests prove the
probe can see a real GenericSuggester.
@chhoumann
chhoumann force-pushed the fix/native-prompt-initial-focus branch from a8fd565 to e323b7d Compare October 24, 2026 09:02
@chhoumann
chhoumann marked this pull request as ready for review October 24, 2026 09:02
@chhoumann
chhoumann merged commit 9bbfb26 into master Oct 24, 2026
10 of 12 checks passed
@chhoumann
chhoumann deleted the fix/native-prompt-initial-focus branch October 24, 2026 09:14
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