Skip to main content

Text Selection

Text selection allows users to highlight document text by dragging, double-clicking, or triple-clicking. The selection state lives in InteractionState::selection.

TextCursor and TextSelection

pub struct TextCursor {
pub path: Vec<usize>, // Path to the text LayoutBox
pub glyph_index: usize, // Index into the glyph array
}

pub struct TextSelection {
pub anchor: TextCursor, // Where the drag started
pub focus: TextCursor, // Where the drag is currently
}

A selection where anchor == focus is collapsed (no visible highlight). The selection highlight is painted across all text runs between anchor and focus in document order.

Drag-to-Select

Primary-button drag sets InteractionState::selecting_text = true and updates focus:

tree.dispatch_mouse_down(target, pos, MouseButton::Primary, cursor);
// On move while primary is down:
tree.dispatch_mouse_move_with_selection(target, pos, cursor);

Selection highlight quads are painted per line within the affected text runs. The highlight color is configurable via SelectionColors.

select_all_text / selected_text

// Ctrl+A
wgpu_html::select_all_text(&mut tree, &layout);

// Get selected text for clipboard
if let Some(text) = wgpu_html::selected_text(&tree, &layout) {
// Copy to clipboard...
}

select_all_text() finds the first and last text cursors in document order and sets a selection spanning them. selected_text() extracts the visible text from the selection range.

Word Select (Double-Click)

Double-clicking selects the word under the pointer:

wgpu_html::select_word_at_cursor(&mut tree, &layout, &cursor);

Word boundaries use char::is_alphanumeric and _ as word characters. Whitespace and punctuation form separate tokens.

Line Select (Triple-Click)

Triple-clicking selects the entire shaped line:

wgpu_html::select_line_at_cursor(&mut tree, &layout, &cursor);

This selects all glyphs in the ShapedLine containing the hit cursor.

Selection Highlight

The paint stage emits filled quads behind selected text:

// Background highlight quad per selected glyph range
list.push_quad(Quad {
rect: highlight_rect,
color: selection_colors.background,
radii_h: [0.0; 4], radii_v: [0.0; 4],
stroke: [0.0; 4], pattern: [0.0; 4],
});

The highlight is painted before glyphs, so text appears on top. Selection colors default to browser-like blue highlight with white text.

user-select: none

.unselectable { user-select: none; }

LayoutBox::user_select suppresses selection for a box and its descendants. The hit test and paint both skip boxes with user_select == UserSelect::None.

Ctrl+A / Ctrl+C

ShortcutAction
Ctrl+Aselect_all_text() — selects all text in the document
Ctrl+CCopies selected_text() to the OS clipboard via arboard

These are handled in the default key_down dispatch. Hosts using WgpuHtmlWindow get them automatically; custom integrations add them manually.