Skip to content

Feature Request: SelectionArea — cross-element text selection container (like Flutter's SelectionArea) #2110

@ghjdegithub

Description

@ghjdegithub

Problem

Currently, TextView supports .selectable(true) for intra-element text selection and copy, which works great within a single TextView. However, there is no way to select text across multiple elements — for example, selecting a Label, a TextView, and another Label together with a single mouse drag.

This is a common pattern in desktop applications. For comparison:

  • egui: All text in a window is part of a unified drawing context, so cross-widget text selection works natively.
  • Web browsers: Users can select text across multiple <div>, <p>, <span> elements seamlessly.
  • Flutter: Initially had the same limitation (per-widget selection only). Solved in Flutter 3.3 by introducing SelectionArea — a parent widget that enables cross-widget text selection for all Selectable descendants.

Proposed Solution

Introduce a SelectionArea container element (similar to Flutter's approach):

// Wrap a section of UI to enable cross-element text selection
SelectionArea::new("my-selection-area", |area| {
    area.child(Label::new("Title").text_lg())
        .child(Label::new("Some body text"))
        .child(Label::new(format!("Counter: {}", counter)))
})

How it could work (referencing Flutter's architecture):

  1. Selectable trait: Text-bearing elements (Label, TextView, etc.) implement a Selectable trait, registering their text content and layout bounds with the parent SelectionArea.
  2. SelectionArea container: Intercepts mouse drag events, maintains a unified selection range across child Selectable elements, and renders per-element selection highlights.
  3. Copy support: Cmd+C / Ctrl+C within the area concatenates selected text from all children in DOM order and writes to clipboard.

Key design considerations:

  • Only text-bearing elements participate; buttons, inputs, sliders, etc. are skipped during selection.
  • The selection area should handle scrollable content correctly.
  • Nested SelectionArea containers should be supported.

Current Workaround

Merge multiple text items into a single TextView::markdown(...) using \n\n for paragraph breaks:

// Instead of separate Labels:
// .child(Label::new("Line 1"))
// .child(Label::new("Line 2"))

// Merge into one selectable markdown block:
.child(TextView::markdown("id", "Line 1\n\nLine 2", window, cx).selectable(true))

This works but loses individual styling control, can't span across non-text elements (like dividers or buttons), and conflates logical structure.

Environment

  • gpui: 0.2.2
  • gpui-component: 0.5.1
  • Platform: macOS (Apple Silicon)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions