You can track keyboard focus on a View and detect when elements on the page accept typed text.

This tells you when to forward keyboard events to the page, when to reserve keys for game shortcuts, and when to display an on-screen keyboard.

## Managing Focus in AppCore

AppCore windows manage focus across their panels automatically.

Call `Panel::Focus()` to give keyboard focus to a panel, and `Window::ClearFocus()` to clear focus from every panel in the window.

The window runs the OS input method on its own. To display an on-screen keyboard, register a callback with `Window::OnEditableStateChange()`.

> 🚧 Do Not Replace the Editor Listener
>
> AppCore installs an editor listener on each panel's View to run the window's input method. Never call `View::set_editor_listener()` on a panel's View— doing so turns off input method support and stops `Window::OnEditableStateChange()` callbacks for that panel.

The rest of this page covers Views you host directly.

## Focusing a View

Call `View::Focus()` when the native window gains keyboard focus, and `View::Unfocus()` when it loses focus.

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

using namespace ultralight;

RefPtr<View> view;

///
/// Called by our window when it gains or loses the keyboard.
///
void OnWindowFocusChanged(bool focused) {
  if (focused)
    view->Focus();
  else
    view->Unfocus();
}
```

A new View starts with focus by default (`ViewConfig::initial_focus`). The caret blinks only while the View has focus— without it, text selections remain visible in an inactive gray.

Calling `View::Unfocus()` fires a `blur` event on the active element while keeping it focused in the document— calling `View::Focus()` later brings its caret back.

## Checking for Text Input Focus

You can call `View::HasInputFocus()` to check whether an element on the page is actively waiting for typed text.

It returns `true` while a text field, multi-line text area, or editable element holds keyboard focus and accepts text entry.

### When the Call Returns False

The call returns `false` for elements that don't accept typed characters, including buttons, checkboxes, dropdowns, and read-only text fields.

It also returns `false` whenever the View itself is unfocused— even if an editable element remains focused in the document.

### Routing Keyboard Input

In games with a heads-up display, you can use `View::HasInputFocus()` to decide whether the page or the game receives keystrokes.

Forward keyboard events to the View only while `View::HasInputFocus()` is `true`— this lets players type into chat boxes without triggering game movement or hotkeys.

When a menu or dialog opens, forward every key to the View— buttons and dropdowns still need keys like Tab, Space, Enter, and the arrows.

For a full keyboard routing walkthrough, see [Integrating into a Game Engine](/docs/2.0/integrating-into-a-game-engine).

## Listening for Editable State Changes

To track editable state changes, implement `EditorListener` and register an instance with `View::set_editor_listener()`.

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

using namespace ultralight;

class MyApp : public EditorListener {
 public:
  ///
  /// Show or hide our on-screen keyboard as the page's editable state changes.
  ///
  void OnChangeEditableState(View* caller,
                             const EditableState& state) override {
    ///
    /// A keyboard belongs up only while the View has focus and the focused
    /// element accepts typed input.
    ///
    bool wants_keyboard = state.view_has_focus && state.is_mutable;

    if (!wants_keyboard) {
      // Pseudo-code, hide your on-screen keyboard here.
      HideOnScreenKeyboard();
      return;
    }

    ///
    /// Convert the element's bounds to device pixels and park the keyboard
    /// just below it, with the layout the page asked for.
    ///
    double scale = caller->device_scale();
    double x = state.bounds.left * scale;
    double y = state.bounds.bottom * scale;

    // Pseudo-code, show your on-screen keyboard here.
    ShowOnScreenKeyboard(x, y, state.input_mode, state.enter_key_hint);
  }
};

MyApp app;

void AttachListener(View* view) {
  ///
  /// Hand the View a pointer to our listener.
  /// (Ownership stays with us, so 'app' must outlive its use by the View.)
  ///
  view->set_editor_listener(&app);
}
```

### When the Callback Fires

The library calls `EditorListener::OnChangeEditableState()` whenever keyboard focus moves to another element, when the View gains or loses focus, and when the focused element's `inputmode` attribute changes.

The callback does not fire when an element moves or resizes on screen— use `Editor::GetCaretBounds()` to follow the caret.

> 🚧 Avoid State Changes in Callbacks
>
> The library can call `OnChangeEditableState()` from inside `View::Focus()` or `View::Unfocus()`. Inspect the state during the callback, but wait until it returns before modifying focus, navigating, or altering page content.

### Reading the Editable State

The `EditableState` struct describes whether the focused element accepts text, what keyboard layout it requests, and where it appears on screen.

#### Showing or Hiding a Keyboard

An on-screen keyboard or input method should stay active only while `view_has_focus` and `is_mutable` are both `true`. When either property is `false`, you should hide the keyboard.

#### Reading Input Hints

The page provides hints that help you configure the on-screen keyboard.

- `type` — the kind of element holding focus (eg, `EditableType::Password`).
- `input_mode` — the keyboard layout requested by the page (eg, numeric or email).
- `enter_key_hint` — the action label or icon requested for the Enter key (eg, done or send).

#### Locating the Element

The `bounds` property gives the focused element's rectangle in viewport CSS pixels— the same coordinate space used by mouse events. When no element has focus, all coordinates in `bounds` are zero.

To convert these coordinates to device pixels for native UI, multiply the values by `View::device_scale()`.

If you support an OS input method rather than an on-screen keyboard, see [Input Method Editors](/docs/2.0/input-method-editors).
