Skip to content

[css-ui] Allow customization of the text cursor selected by cursor: auto #14178

Open

Description

@ylemkimon

Problem

CSS allows authors to specify a custom cursor:

.editor {
  cursor: url("custom-ibeam.svg") 8 12, text;
}

However, CSS selectors cannot select text nodes. The author therefore cannot express:

Apply this custom cursor when the pointer is over a selectable text node.

The current CSS UI specification defines cursor: auto as follows:

The UA determines the cursor to display based on the current context: auto behaves as text over selectable text or editable elements, and default otherwise.

Using auto as the fallback does not preserve that behavior:

.editor {
  cursor: url("custom-ibeam.svg") 8 12, auto;
}

The custom image is selected first. auto is used only if the image cannot be used. This is confusing to users and may hurt accessibility when a custom cursor is used.

There is no way to customize only the text cursor that the browser selects as part of cursor: auto.

Chromium behavior

Chromium performs a hit test and identifies a text node directly. Its logic is:

bool EventHandler::ShouldShowIBeamForNode(const Node* node,
                                          const HitTestResult& result) {
  if (!node)
    return false;

  if (node->IsTextNode() && (node->CanStartSelection() || result.IsOverLink()))
    return true;

  return IsEditable(*node);
}

https://github.com/chromium/chromium/blob/6a5b476f4d08479557fb700b0528e33fede76623/third_party/blink/renderer/core/input/event_handler.cc#L560-L569

This uses information unavailable to CSS, including whether the hit-tested node is a text node and whether selection can start from it.

Why existing CSS and JavaScript are insufficient

CSS selectors cannot match text nodes (#2208). Wrapping every text node in an element is not generally practical and still would not reproduce the browser’s selection logic.

JavaScript cannot fully reproduce the behavior either:

  • getComputedStyle().cursor returns auto, not the final selected cursor;
  • internal checks such as CanStartSelection() are not exposed;
  • native controls, generated content, shadow trees, and internal layout objects may affect cursor selection;
  • emulating this with continuous pointer-move hit testing and style updates introduce performance overhead and cursor flicker.

The browser already determines when a text cursor is appropriate, but CSS cannot customize the result of that determination.

Proposal

Add a text-cursor property:

.editor {
  cursor: auto;
  text-cursor: url("custom-ibeam.svg") 8 12, text;
}

The syntax would be identical to cursor.

When the browser’s automatic cursor-selection algorithm chooses a text cursor, it would use the value of text-cursor. Otherwise, normal cursor behavior would remain unchanged.

cursor = resolve cursor normally

if cursor was automatically resolved to text
    and text-cursor is not auto:
  cursor = resolve text-cursor

The initial value would be auto, meaning the platform text cursor. The property should inherit, like cursor.

Alternative: cursor-auto

A more general alternative would allow authors to replace any predefined cursor selected by auto:

.editor {
  cursor: auto;
  cursor-auto:
    text: url("custom-ibeam.svg") 8 12, text;
}

This is more extensible, but also introduces a larger and more complex feature.

Disclaimer: This proposal was drafted with assistance from an LLM.

Activity

  1. Crissov commented on Jul 15, 2026

    @Crissov
    Contributor

    Also se #13869, where I suggested that stuff like that might best be solved by a new @cursor at-rule.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions