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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions