Proposal: `setCaretInlineOffset` API for adjusting caret visual representation

Open
#347 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
35/100
Issue type
Feature
Clarity
Mostly clear
Activity status
Stale
Tech stack
html
Domain
api, frontend

Research direction

The issue names no repository files or tests. Start by reading the Selection API's Selection interface and the proposed setCaretInlineOffset examples; done would require an agreed API design and defined specification or test changes, which the issue does not yet provide.

Written by the indexing model from the issue text.

Description

Problem

Rich text editors face challenges with caret positioning when text is broken into multiple line boxes due to responsive layouts, because a single boundary point can be visually rendered in 2 different places.

For example, a boundary-point like {node: #text, offset: 5} in the following HTML:

<p style="word-break: break-all">loremipsum</p>

Image

When we use the browser's default event to navigate, it uses its "internal state" to know where the caret should be placed. However, if we want to implement the block-directional / inline-directional navigation manually, we have no control over the caret's visual placement.

Proposal

I'd like to propose to extend the Selection API by adding a new method that allows developers to set an inline offset for the caret’s visual appearance.

interface Selection {
  setCaretInlineOffset: (offset: number) => void;
}
How would it work?

It checks if the caret should be appeared, then
if the caret can be placed in 2 different places, then
if the diff between offsetA and offset is smaller than the diff between offsetB and offset, position the caret to the place A, otherwise position it to the place B.

Example
const textNode = document.createTextNode("loremipsum");

// We get the char's left and right pos
const getCharPos = (text, index) => {
	const range = new Range();

	range.setStart(text, index);
	range.setEnd(text, index + 1);

	const { left: charLeftPos, right: charRightPos } =
		range.getBoundingClientRect();

	return { charLeftPos, charRightPos };
};

// We select the char m (lore[m]ipsum)
const char_M_Pos = getCharPos(textNode, 4);

// We select the char i (lorem[i]psum)
const char_I_Pos = getCharPos(textNode, 5);

const sel = getSelection();

// Set the bp to lorem|ipsum
sel.setPosition(textNode, 5);

// If we want to adjust right after lorem
sel.setCaretInlineOffset(char_M_Pos.charRightPos);

// If we want to adjust right before ipsum
sel.setCaretInlineOffset(char_I_Pos.charLeftPos);
Dominant language
HTML
Stars
49
Forks
30
PR merge metrics
No merged PRs in 30d

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.

More from w3c/selection-api

All issues in w3c/selection-api

Similar issues

More Backend & API Design issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.