From bb5c62b4974ce39d9af7d171f1e224d713d36cbd Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Tue, 18 Aug 2026 15:52:08 +0200 Subject: [PATCH 1/2] Fixed input in create link button popover closing keyboard. --- .../01-basic/04-default-blocks/src/App.tsx | 64 ++++++++++++++++++- packages/ariakit/src/input/TextInput.tsx | 2 + packages/mantine/src/form/TextInput.tsx | 2 + .../LinkToolbar/EditLinkMenuItems.tsx | 20 +++++- .../react/src/editor/ComponentsContext.tsx | 1 + packages/shadcn/src/form/TextInput.tsx | 2 + 6 files changed, 89 insertions(+), 2 deletions(-) diff --git a/examples/01-basic/04-default-blocks/src/App.tsx b/examples/01-basic/04-default-blocks/src/App.tsx index 0d55d1af3d..728e6485f0 100644 --- a/examples/01-basic/04-default-blocks/src/App.tsx +++ b/examples/01-basic/04-default-blocks/src/App.tsx @@ -2,6 +2,8 @@ import "@blocknote/core/fonts/inter.css"; import { BlockNoteView } from "@blocknote/mantine"; import "@blocknote/mantine/style.css"; import { useCreateBlockNote } from "@blocknote/react"; +import { Button, Popover, Text, TextInput } from "@mantine/core"; +import { useRef } from "react"; export default function App() { // Creates a new editor instance. @@ -148,6 +150,66 @@ export default function App() { ], }); + const inputRef = useRef(null); + // Renders the editor instance using a React component. - return ; + return ( + <> + {/**/} + + + + + + + This is uncontrolled popover, it is opened when button is clicked + + + + + +
+ + + + + + + This is uncontrolled popover, it is opened when button is clicked + + { + console.log(e.target instanceof HTMLInputElement); + if (e.target instanceof HTMLInputElement) { + e.target.scrollIntoView(); + } + }} + /> + + + + ); } diff --git a/packages/ariakit/src/input/TextInput.tsx b/packages/ariakit/src/input/TextInput.tsx index 555961faf0..0f3019e208 100644 --- a/packages/ariakit/src/input/TextInput.tsx +++ b/packages/ariakit/src/input/TextInput.tsx @@ -23,6 +23,7 @@ export const TextInput = forwardRef< disabled, onKeyDown, onChange, + onClickCapture, onSubmit, autoComplete, "aria-activedescendant": ariaActivedescendant, @@ -51,6 +52,7 @@ export const TextInput = forwardRef< disabled={disabled} onKeyDown={onKeyDown} onChange={onChange} + onClickCapture={onClickCapture} onSubmit={onSubmit} autoComplete={autoComplete} aria-activedescendant={ariaActivedescendant} diff --git a/packages/mantine/src/form/TextInput.tsx b/packages/mantine/src/form/TextInput.tsx index c1630fa17f..3bd844145d 100644 --- a/packages/mantine/src/form/TextInput.tsx +++ b/packages/mantine/src/form/TextInput.tsx @@ -20,6 +20,7 @@ export const TextInput = forwardRef< disabled, onKeyDown, onChange, + onClickCapture, onSubmit, autoComplete, "aria-activedescendant": ariaActivedescendant, @@ -48,6 +49,7 @@ export const TextInput = forwardRef< disabled={disabled} onKeyDown={onKeyDown} onChange={onChange} + onClickCapture={onClickCapture} onSubmit={onSubmit} autoComplete={autoComplete} aria-activedescendant={ariaActivedescendant} diff --git a/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx b/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx index 1d82a6e7cc..2145ff641e 100644 --- a/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx +++ b/packages/react/src/components/LinkToolbar/EditLinkMenuItems.tsx @@ -6,12 +6,14 @@ import { import { ChangeEvent, KeyboardEvent, + MouseEvent, useCallback, useEffect, useState, } from "react"; import { RiLink, RiText } from "react-icons/ri"; import { useComponentsContext } from "../../editor/ComponentsContext.js"; +import { useBlockNoteEditor } from "../../hooks/useBlockNoteEditor.js"; import { useExtension } from "../../hooks/useExtension.js"; import { useDictionary } from "../../i18n/dictionary.js"; import { LinkToolbarProps } from "./LinkToolbarProps.js"; @@ -36,6 +38,7 @@ export const EditLinkMenuItems = ( ) => { const Components = useComponentsContext()!; const dict = useDictionary(); + const editor = useBlockNoteEditor(); // eslint-disable-next-line @typescript-eslint/unbound-method -- editLink is a plain object method, not a class method const { editLink } = useExtension(LinkToolbarExtension); @@ -80,6 +83,19 @@ export const EditLinkMenuItems = ( props.setToolbarPositionFrozen?.(false); }, [editLink, currentUrl, currentText, props]); + // Scrolling the input into view works around an Android Chrome issue where + // the input is otherwise left hidden behind the on-screen keyboard. We then + // restore the scroll position to the editor selection. + const handleClickCapture = useCallback( + (event: MouseEvent) => { + event.currentTarget.scrollIntoView(); + setTimeout(() => { + editor.transact((tr) => tr.scrollIntoView()); + }, 1000); + }, + [editor], + ); + return ( {/* // TODO: add labels? */} @@ -87,11 +103,12 @@ export const EditLinkMenuItems = ( className={"bn-text-input"} name="url" icon={} - autoFocus={true} + autoFocus={false} placeholder={dict.link_toolbar.form.url_placeholder} value={currentUrl} onKeyDown={handleEnter} onChange={handleUrlChange} + onClickCapture={handleClickCapture} onSubmit={handleSubmit} /> {showTextField !== false && ( @@ -103,6 +120,7 @@ export const EditLinkMenuItems = ( value={currentText} onKeyDown={handleEnter} onChange={handleTextChange} + onClickCapture={handleClickCapture} onSubmit={handleSubmit} /> )} diff --git a/packages/react/src/editor/ComponentsContext.tsx b/packages/react/src/editor/ComponentsContext.tsx index 4b60483d43..53f0a9b00d 100644 --- a/packages/react/src/editor/ComponentsContext.tsx +++ b/packages/react/src/editor/ComponentsContext.tsx @@ -317,6 +317,7 @@ export type ComponentProps = { value: string; onKeyDown: (event: KeyboardEvent) => void; onChange: (event: ChangeEvent) => void; + onClickCapture?: (event: MouseEvent) => void; onSubmit?: () => void; autoComplete?: HTMLInputAutoCompleteAttribute; "aria-activedescendant"?: string; diff --git a/packages/shadcn/src/form/TextInput.tsx b/packages/shadcn/src/form/TextInput.tsx index 675e7409fa..56ec10be0b 100644 --- a/packages/shadcn/src/form/TextInput.tsx +++ b/packages/shadcn/src/form/TextInput.tsx @@ -21,6 +21,7 @@ export const TextInput = forwardRef< disabled, onKeyDown, onChange, + onClickCapture, onSubmit, autoComplete: _autoComplete, "aria-activedescendant": ariaActivedescendant, @@ -57,6 +58,7 @@ export const TextInput = forwardRef< value={value} onKeyDown={onKeyDown} onChange={onChange} + onClickCapture={onClickCapture} onSubmit={onSubmit} ref={ref} aria-activedescendant={ariaActivedescendant} From cdf5e4d97f222b4b375b5184a3b28f527f77e0ec Mon Sep 17 00:00:00 2001 From: Matthew Lipski Date: Tue, 18 Aug 2026 16:11:31 +0200 Subject: [PATCH 2/2] Reverted example --- .../01-basic/04-default-blocks/src/App.tsx | 60 +------------------ 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/examples/01-basic/04-default-blocks/src/App.tsx b/examples/01-basic/04-default-blocks/src/App.tsx index 728e6485f0..872555abd7 100644 --- a/examples/01-basic/04-default-blocks/src/App.tsx +++ b/examples/01-basic/04-default-blocks/src/App.tsx @@ -153,63 +153,5 @@ export default function App() { const inputRef = useRef(null); // Renders the editor instance using a React component. - return ( - <> - {/**/} - - - - - - - This is uncontrolled popover, it is opened when button is clicked - - - - - -
- - - - - - - This is uncontrolled popover, it is opened when button is clicked - - { - console.log(e.target instanceof HTMLInputElement); - if (e.target instanceof HTMLInputElement) { - e.target.scrollIntoView(); - } - }} - /> - - - - ); + return ; }