RocketChat / RocketChat/Rocket.Chat

Composer auto-grow: scroll-to-bottom check uses strict equality, breaks on fractional scrollTop (high-DPI/zoom)

Open Beginner friendly
#42,256 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type: bug
Dominant language
TypeScript
Stars
46.1k
Forks
13.9k
Avg merge
3d 3h
Merged PRs (30d)
130

Description

Description:

The message composer's auto-grow logic decides whether to keep the caret pinned to the bottom using shouldScrollToBottom in apps/meteor/client/views/room/composer/RoomComposer/hooks/useAutoGrow.ts:

function shouldScrollToBottom(textarea: HTMLTextAreaElement) {
	const isCursorAtBottom = textarea.selectionEnd === textarea.value.length;
	const isScrolledToBottom = textarea.scrollTop + textarea.clientHeight === textarea.scrollHeight;

	return isCursorAtBottom || isScrolledToBottom;
}

The isScrolledToBottom check uses strict equality (===) against scrollTop + clientHeight === scrollHeight. scrollTop is a fractional value on high-DPI displays and at non-100% browser zoom, so scrollTop + clientHeight frequently does not exactly equal scrollHeight even when the textarea is visually scrolled all the way down. When that happens isScrolledToBottom is wrongly false.

If the caret is also not at the very end of the text (isCursorAtBottom === false — e.g. the user clicked into the middle of a long draft, or an autocomplete/emoji insert moved it), shouldScrollToBottom returns false and useAutoGrow's resize() skips the node.scrollTop = node.scrollHeight correction — so as the textarea grows, the caret/last line can drift out of view.

The widely-used "scrolled to bottom" idiom accounts for the fractional pixel with a small tolerance:

const isScrolledToBottom = textarea.scrollTop + textarea.clientHeight >= textarea.scrollHeight - 1;
Steps to reproduce:
  1. Use a high-DPI display or set browser zoom to e.g. 110%/125% (so scrollTop becomes fractional).
  2. Open any channel and type a multi-line message until the composer textarea grows a scrollbar.
  3. Place the caret somewhere before the end of the text (so selectionEnd !== value.length) while the textarea is scrolled to the bottom.
  4. Keep typing so the textarea keeps growing.
Expected behavior:

While the textarea is scrolled to the bottom, it stays pinned to the bottom (the caret/last line remains visible) as it grows.

Actual behavior:

Because scrollTop + clientHeight === scrollHeight is false for fractional scrollTop, the auto-grow scroll correction is skipped and the content can drift so the caret/last line is no longer visible.

Server Setup Information:
  • Version of Rocket.Chat Server: develop (client-side bug, server-version independent)
Client Setup Information:
  • Browser: any (Chrome/Edge/Firefox) on a high-DPI display or with browser zoom ≠ 100%
  • Rocket.Chat web client, message composer (MessageBoxuseAutoGrow)
Additional context
  • Component path: apps/meteor/client/views/room/composer/messageBox/MessageBox.tsx (line ~271) → useAutoGrowshouldScrollToBottom.
  • Fix is a one-line tolerance change in the scroll comparison.
  • I'd like to work on this and will open a PR with a regression test.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in apps/meteor/client/views/room/composer/RoomComposer/hooks/useAutoGrow.ts, following shouldScrollToBottom and resize; use MessageBox.tsx as the entry point. Add the reported fractional-scroll regression coverage and verify that a textarea already at the bottom remains pinned as it grows when the caret is not at the end.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.