You can control text editing, selections, and clipboard actions on a page using the View's editor. This lets you connect native Edit menus, context menus, toolbar buttons, and on-screen keyboards directly to the focused element.

Standard keyboard shortcuts like Ctrl+C and Ctrl+V already run when you forward key events (see [Keyboard Input](/docs/2.0/keyboard-input)). The editor provides programmatic control over the same operations, with or without AppCore.

## Running Editing Commands

Call `View::editor()` to obtain the View's `Editor` instance. Calling `Editor::Execute()` with an `EditorCommand` runs that command on the focused frame— it returns `false` if the command cannot run (such as copying without a selection or undoing with an empty history).

To copy the current selection:

```cpp
#include <Ultralight/Ultralight.h>

using namespace ultralight;

RefPtr<Renderer> renderer;
RefPtr<View> view;

///
/// Copy the page's selection, the way the Edit menu's Copy item would.
///
void CopySelection() {
  Editor* editor = view->editor();
  editor->Execute(EditorCommand::Copy);
}
```

### Available Commands

The `EditorCommand` enum groups editing actions by function.

| Group | Commands |
| :--- | :--- |
| Clipboard and history | `Cut`, `Copy`, `Paste`, `PasteAsPlainText`, `SelectAll`, `Undo`, `Redo` |
| Caret motion | `MoveLeft`, `MoveWordRight`, `MoveToEndOfLine`, `MovePageDown` |
| Selection | `SelectWord`, `SelectLine`, `SelectParagraph`, `Unselect` |
| Deletion | `DeleteBackward`, `DeleteForward`, `DeleteWordBackward`, `DeleteToEndOfLine` |
| Insertion | `InsertNewline`, `InsertLineBreak`, `InsertTab`, `InsertBacktab` |

Every caret motion also provides an `AndModifySelection` variant (such as `MoveLeftAndModifySelection`) that extends the current selection, matching Shift-key behavior.

### Inserting Text

To insert text at the caret, call `Editor::InsertText()`. The string replaces any active selection, exactly as if the user had typed it.

To forward text from an on-screen keyboard:

```cpp
///
/// Called by our on-screen keyboard when the player taps a key.
///
void OnScreenKeyTapped(const String& text) {
  view->editor()->InsertText(text);
}
```

## Building Edit and Context Menus

Call `Editor::CanExecute()` before displaying a menu to determine whether to enable or disable individual items.

To update menu item states and dispatch the selected command:

```cpp
///
/// Enable or grey out each item just before the menu opens.
///
void UpdateEditMenu() {
  Editor* editor = view->editor();

  // Pseudo-code, enable or disable the items in your own menu here.
  SetMenuItemEnabled("Cut", editor->CanExecute(EditorCommand::Cut));
  SetMenuItemEnabled("Copy", editor->CanExecute(EditorCommand::Copy));
  SetMenuItemEnabled("Paste", editor->CanExecute(EditorCommand::Paste));
  SetMenuItemEnabled("Undo", editor->CanExecute(EditorCommand::Undo));
  SetMenuItemEnabled("Redo", editor->CanExecute(EditorCommand::Redo));
}

///
/// Run the command behind the item the user picked.
///
void OnEditMenuCommand(EditorCommand command) {
  view->editor()->Execute(command);
}
```

### Positioning Menus at the Caret

To position a context menu at the caret, retrieve its bounds from the editor:

```cpp
///
/// Open a right-click menu just below the caret.
///
void ShowContextMenu() {
  Rect caret = view->editor()->GetCaretBounds();
  double scale = view->device_scale();

  // Pseudo-code, open your menu at this position within the View.
  OpenContextMenu(caret.left * scale, caret.bottom * scale);
}
```

`Editor::GetCaretBounds()` returns the caret's rectangle in viewport CSS pixels rather than screen coordinates— the same coordinate system used for mouse events (see [Mouse and Scroll Input](/docs/2.0/mouse-and-scroll-input)).

When the page has no active caret, all fields in the rectangle are zero.

> 📘 Avoid Polling Every Frame
>
> Calling `Editor::GetCaretBounds()` updates any pending layout first. Query the bounds when opening a menu rather than polling every frame.

## Managing the Clipboard

Editing commands like `Cut`, `Copy`, and `Paste` use the platform clipboard. `App::Create()` sets up the OS clipboard automatically— without AppCore, you must provide one by calling `Platform::set_clipboard()` (see [Clipboard Integration](/docs/2.0/clipboard-integration)).

### Controlling Script Clipboard Access

The `ViewConfig::clipboard_read_policy` setting restricts which pages can read the clipboard from script (such as a page button calling `document.execCommand('paste')`). The library only evaluates these requests during user gestures like clicks or key presses. Pastes triggered directly by the user or through `Editor::Execute()` are never affected.

| Policy | Grants Reads From |
| :--- | :--- |
| `ClipboardReadPolicy::AllowForAppContent` (default) | Local `file:///` pages and content you supply directly (eg, `View::LoadHTML()`) |
| `ClipboardReadPolicy::Allow` | Any page |
| `ClipboardReadPolicy::Deny` | No page |

To allow script on any page to read the clipboard during a user gesture:

```cpp
///
/// Let any page read the clipboard during a click or key press.
///
void CreateView() {
  ViewConfig config;
  config.clipboard_read_policy = ClipboardReadPolicy::Allow;
  view = renderer->CreateView(800, 600, config, nullptr);
}
```

> 🚧 Restrict Untrusted Content
>
> Setting `ClipboardReadPolicy::Allow` lets any loaded page read clipboard contents, including remote web pages. Use it only when the View displays trusted content.

## Matching Native Editing Behavior

By default, `ViewConfig::match_native_editing_behavior` is `false`, providing identical text selection and editing behavior across all platforms. Setting this field to `true` adopts the host OS's native editing conventions (such as macOS-style Shift-click selection extension).

Views created automatically by AppCore for `AddPanel()` enable this setting through `Settings::match_native_editing_behavior`. If you pass an explicit `ViewConfig`, the View uses the value specified in that configuration instead.
