Skip to content

fix(core): keep collaboration cursor labels visible in tables and at screen edges - #3227

Open
YousefED wants to merge 1 commit into
mainfrom
fix/collab-cursor-labels
Open

YousefED wants to merge 1 commit into
mainfrom
fix/collab-cursor-labels

Conversation

@YousefED

@YousefED YousefED commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #3079. This is an alternative to #3095.

Problem

The label of a remote cursor was cut off:

  • in a table, because the table's scroll container clips it,
  • at the top and at the right edge of the screen.

Solution

The label is position: fixed, so a scroll container does not clip it. CSS anchor positioning attaches the label to its caret, so the label follows the caret when the page scrolls or the text moves. The editor does not need code to position the label.

When the label opens, showCursorLabel picks its side:

  • above the caret, or below it if there is no space at the top of the screen,
  • from the caret to the right, or to the left if there is no space at the right edge.

CSS uses this side (data-placement) for the position, for the corner from which the label grows, and for its square corner at the caret. The browser does not flip the label (position-try-fallbacks): it keeps a flipped side after the caret moves away from the edge, and CSS cannot tell which side the browser picked.

The closed label is the marker at the top of the caret, as before. It opens and closes with an animation, as before.

Browsers without anchor positioning show the label as before (@supports). The table and the edges of the screen can still clip it in these browsers.

Other changes

  • showCursorLabels: "always" did not show the labels. Now it shows them.
  • A label now opens while the collaborator types. Before, it opened only when the collaborator moved the cursor. Typing does not change a cursor in Yjs, because the position is relative to the text. The plugins now also find the authors of remote edits in the Yjs document.
  • The Yjs 14 cursor plugin now removes its listeners when the editor unmounts.

Compared with #3095

#3095 also uses CSS anchor positioning, but it moves the labels into the portal element. This PR keeps each label in its cursor. Thus, it does not need to sync labels with the awareness state, and it does not change the structure of the two cursor plugins. Also, it does not use @container anchored, which only Chromium supports.

Known limitations

  • When a label is open, the editor does not pick its side again after a scroll, a resize, or a change of the layout. The label can go off the screen until the cursor moves or the collaborator types again. This mostly affects showCursorLabels: "always".
  • Backspace does not open the label. The cursor position does not change, because it is relative to the next character. Also, Yjs does not record who deleted content. The Delete key opens the label, because it changes the cursor position.

Tests

  • New browser tests for Yjs 13 (cursorLabel.browser.test.ts): a label in a table, at the top and at the right edge of the screen, after the cursor moves away from the right edge, while a collaborator types, and with showCursorLabels: "always".
  • New browser tests for Yjs 14 (YCursorPlugin.browser.test.ts): a label after a cursor move, while a collaborator types, with showCursorLabels: "always", and the removal of the listeners.
  • The new tests pass in Chromium, Firefox, and WebKit. The tests for the fixed behavior fail on main.
  • An editor in a shadow root works without other changes.
  • Performance in Chromium: each cursor move adds approximately 0.1 ms of layout, and each remote edit adds approximately 0.06 ms of script. Scrolling with 20 open labels needs no layout and no style recalculation.

@vercel

vercel Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
blocknote Ready Ready Preview Oct 22, 2026 7:30am UTC
blocknote-website Ready Ready Preview Oct 22, 2026 7:30am UTC

Request Review

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 87768a9a-03fb-48b1-8099-1ffa6b4ef423
📥 Commits

Reviewing files that changed from the base of the PR and between 45d07d3 and 1f65d48.

📒 Files selected for processing: 6
  • packages/core/src/editor/editor.css
  • packages/core/src/extensions/Collaboration/cursorLabel.ts
  • packages/core/src/y/extensions/YCursorPlugin.browser.test.ts
  • packages/core/src/y/extensions/YCursorPlugin.ts
  • packages/core/src/yjs/extensions/YCursorPlugin.ts
  • packages/core/src/yjs/extensions/cursorLabel.browser.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

Collaborative cursor labels now use viewport-aware floating placement when CSS anchor positioning is supported. Awareness updates and remote document transactions update label visibility, with a two-second timeout unless labels are set to "always". Browser tests cover placement, visibility, and listener cleanup.

Changes: Collaborative cursor labels

Layer / File(s) Summary
Floating label placement
packages/core/src/extensions/Collaboration/cursorLabel.ts, packages/core/src/editor/editor.css
Helpers anchor labels to carets, select placement based on available viewport space, and control active state. Supported browsers use floating styles that hide labels when their caret is outside the visible area.
Collaboration activity and visibility
packages/core/src/extensions/Collaboration/cursorLabel.ts, packages/core/src/y/extensions/YCursorPlugin.ts, packages/core/src/y/extensions/YCursorPlugin.browser.test.ts, packages/core/src/yjs/extensions/YCursorPlugin.ts, packages/core/src/yjs/extensions/cursorLabel.browser.test.ts
Both cursor extensions update labels after awareness changes and remote document transactions. Browser tests check placement, timeouts, always-visible mode, and listener cleanup.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: nperez0111

Merge Risk: ⚪ Minimal · up to 1f65d

The checked placement and persistent-visibility behavior does not indicate a blocker; this change is ready for normal merge checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Linked Issues check Warning Issue #3079 requires labels to remain visible at the editor right and top edges and inside tables. The supported-browser rules use position: fixed, CSS anchor positioning, and data-placement to pl… Provide an equivalent non-anchor fallback that keeps labels inside the editor at the right and top edges and inside tables, or document and enforce a browser-support requirement that is part of the issue scope.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly summarizes the primary change: keeping collaboration cursor labels visible in tables and at screen edges.
Out of Scope Changes check Passed The changes remain connected to collaborative cursor labels. The showCursorLabels: "always" behavior, labels during remote typing, remoteEditors, lifecycle listener cleanup, and browser tests supp…
Docstring Coverage Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 5 files. (1 skipped: 1 …
Description check Passed The description is detailed and covers the feature, rationale, implementation changes, impacts, known limitations, and testing. It does not use the template headings and omits the checklist and screen…
Full details: Out of Scope Changes check

Explanation

The changes remain connected to collaborative cursor labels. The showCursorLabels: "always" behavior, labels during remote typing, remoteEditors, lifecycle listener cleanup, and browser tests support label visibility and correctness. No unrelated change is established by the supplied diff and file evidence.

Full details: Docstring Coverage

Explanation

Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 5 files. (1 skipped: 1 unsupported.)

Full details: Description check

Explanation

The description is detailed and covers the feature, rationale, implementation changes, impacts, known limitations, and testing. It does not use the template headings and omits the checklist and screenshots section, but the substantive information is mostly complete and directly relevant.

Full details: Linked Issues check

Explanation

Issue #3079 requires labels to remain visible at the editor right and top edges and inside tables. The supported-browser rules use position: fixed, CSS anchor positioning, and data-placement to place labels left or below, and floatCursorLabel applies the anchor. The CSS also uses position-visibility: anchors-visible. However, the implementation places these rules inside @supports (position-anchor: --a) and explicitly retains the clipping inline behavior in browsers without anchor positioning. Issue #3079 does not exclude those browsers, so the requirement is not met for that browser class.

Resolution

Provide an equivalent non-anchor fallback that keeps labels inside the editor at the right and top edges and inside tables, or document and enforce a browser-support requirement that is part of the issue scope.

✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit watched the cursor glide,
Then nudged its label to the side.
Up top, it hopped below the line,
When friends typed on, it stayed in time.
The rabbit thumped, “That label’s fine!”

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@3227

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@3227

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@3227

@blocknote/diagram-block

npm i https://pkg.pr.new/@blocknote/diagram-block@3227

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@3227

@blocknote/math-block

npm i https://pkg.pr.new/@blocknote/math-block@3227

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@3227

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@3227

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@3227

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@3227

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@3227

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@3227

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@3227

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@3227

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@3227

@blocknote/xl-typst-exporter

npm i https://pkg.pr.new/@blocknote/xl-typst-exporter@3227

commit: 1f65d48

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://TypeCellOS.github.io/BlockNote/pr-preview/pr-3227/

Built to branch gh-pages at 2026-10-22 07:48 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

This branch was successfully deployed

2 active deployments
Preview – blocknote-website — 1f65d485 Deployed Oct 22, 2026 by vercel[bot]
Preview – blocknote — 1f65d485 Deployed Oct 22, 2026 by vercel[bot]
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.

Editor label cut off

1 participant