What happened
Edward Saperia reported this bug. Select text in a pad and click the Hyperlink button in the toolbar. The Add link form opens, but focus does not move to the URL field. The reader must click the field before typing.
What we expect
The caret sits in the URL field as soon as the form opens. The reader can type or paste a URL at once, with no extra click.
Steps to reproduce
- Open a pad you can edit.
- Select one word in the text.
- Click Hyperlink in the toolbar. Its tooltip reads "Hyperlink (⌘+K)".
- Type a letter. Expected: the letter appears in the URL field. Reported: it does not.
The report does not name the device. Check desktop first, then a phone.
Acceptance criteria
Blocked by
None — can start now.
Agent brief
Type: AFK for desktop and the Cypress check. The phone check needs a person with a phone.
Category: bug
Current behavior: Reported by Edward Saperia. We have not reproduced it on a dev build yet. Two code paths try to focus the field. Check both.
- The extension opener arms a 100 ms timer in
onShow. The timer focuses content.querySelector('input'). The webapp URL field is a <textarea>, so the query finds nothing.
- The webapp form focuses the field in a mount effect on desktop.
createHyperlinkDesktop returns an empty host, and React portals the form into it. Check whether that effect runs before the popover is attached to the page. A focus() on a detached node does nothing.
The existing webapp create spec never asserts focus. The extension's own clean-room spec asserts it, but only for the extension's built-in form, which uses an <input>.
Desired behavior: Focus lands in the URL field on every open path, on desktop. Phone behavior is recorded, even if the OS blocks it.
Where to start: extensions/extension-hyperlink/src/openers/openCreateHyperlink.ts (onShow, INPUT_FOCUS_DELAY_MS). apps/webapp/src/components/TipTap/hyperlinkPopovers/hooks/useHyperlinkEditorForm.ts (the focus effect). apps/webapp/src/components/TipTap/hyperlinkPopovers/desktopPopoverEntries.ts (createHyperlinkDesktop). apps/webapp/src/components/TipTap/hyperlinkPopovers/HyperlinkPopoverPortal.tsx. apps/webapp/src/components/TipTap/toolbar/desktop/EditorToolbar.tsx (toolbar-hyperlink). apps/webapp/cypress/e2e/editor/hyperlink/hyperlink-create.cy.js. Search by symbol. File names are hints as of 2026-09-29.
Rules that apply: extensions/CLAUDE.md §Webapp-Owned Hyperlink Popovers. The extension stays host-agnostic: the webapp factory returns an HTMLElement and the extension never imports the webapp. extensions/extension-hyperlink/AGENTS.md §Floating Popover. A popover is a one-shot, so build a new one and never reopen a cached one. After any extension source change, run bunx tsup in that package, clear .next, and restart the dev server. AGENTS.md §Test Policy allows this Cypress check because it pins a reported bug. Run it and watch it pass.
Verify: Start make dev-local. Confirm the webapp port first, because it is not always 3000. Open a pad, select a word, click Hyperlink, and type a letter. The letter must appear in the URL field. Then run the create spec with bun run --filter @docs.plus/webapp cypress:run. Add --spec to limit it to hyperlink-create.cy.js. That spec runs on the /editor playground route. Also check a real pad route, because that route mounts the page-level portal.
What happened
Edward Saperia reported this bug. Select text in a pad and click the Hyperlink button in the toolbar. The Add link form opens, but focus does not move to the URL field. The reader must click the field before typing.
What we expect
The caret sits in the URL field as soon as the form opens. The reader can type or paste a URL at once, with no extra click.
Steps to reproduce
The report does not name the device. Check desktop first, then a phone.
Acceptance criteria
hyperlink-editor-urlhas focus.Blocked by
None — can start now.
Agent brief
Type: AFK for desktop and the Cypress check. The phone check needs a person with a phone.
Category: bug
Current behavior: Reported by Edward Saperia. We have not reproduced it on a dev build yet. Two code paths try to focus the field. Check both.
onShow. The timer focusescontent.querySelector('input'). The webapp URL field is a<textarea>, so the query finds nothing.createHyperlinkDesktopreturns an empty host, and React portals the form into it. Check whether that effect runs before the popover is attached to the page. Afocus()on a detached node does nothing.The existing webapp create spec never asserts focus. The extension's own clean-room spec asserts it, but only for the extension's built-in form, which uses an
<input>.Desired behavior: Focus lands in the URL field on every open path, on desktop. Phone behavior is recorded, even if the OS blocks it.
Where to start:
extensions/extension-hyperlink/src/openers/openCreateHyperlink.ts(onShow,INPUT_FOCUS_DELAY_MS).apps/webapp/src/components/TipTap/hyperlinkPopovers/hooks/useHyperlinkEditorForm.ts(the focus effect).apps/webapp/src/components/TipTap/hyperlinkPopovers/desktopPopoverEntries.ts(createHyperlinkDesktop).apps/webapp/src/components/TipTap/hyperlinkPopovers/HyperlinkPopoverPortal.tsx.apps/webapp/src/components/TipTap/toolbar/desktop/EditorToolbar.tsx(toolbar-hyperlink).apps/webapp/cypress/e2e/editor/hyperlink/hyperlink-create.cy.js. Search by symbol. File names are hints as of 2026-09-29.Rules that apply:
extensions/CLAUDE.md§Webapp-Owned Hyperlink Popovers. The extension stays host-agnostic: the webapp factory returns anHTMLElementand the extension never imports the webapp.extensions/extension-hyperlink/AGENTS.md§Floating Popover. A popover is a one-shot, so build a new one and never reopen a cached one. After any extension source change, runbunx tsupin that package, clear.next, and restart the dev server.AGENTS.md§Test Policy allows this Cypress check because it pins a reported bug. Run it and watch it pass.Verify: Start
make dev-local. Confirm the webapp port first, because it is not always 3000. Open a pad, select a word, click Hyperlink, and type a letter. The letter must appear in the URL field. Then run the create spec withbun run --filter @docs.plus/webapp cypress:run. Add--specto limit it tohyperlink-create.cy.js. That spec runs on the/editorplayground route. Also check a real pad route, because that route mounts the page-level portal.