Guide

Input and forms

Devices are read through Unity's Input System once per frame, before your game's Update. The page then gets DOM events in the order, with the targets and the default actions a browser gives.

Pointers

Mouse, touch and pen arrive as pointer events: pointerdown, pointermove, pointerup, pointercancel, pointerover, pointerout, pointerenter, pointerleave, plus click, dblclick, contextmenu, auxclick and wheel. :hover and :active follow them.

Hit testing uses what is painted: transforms, rounded corners, clips, clip-path, pointer-events and visibility all count.

// Did the UI take the mouse this frame? Use it to keep clicks from reaching the game world.
if (UiSystem.Input.TryGetMouseView(out var view, out var position)) return;

Pointer capture

SetPointerCapture sends a pointer's events to one element until the button is released, even when the pointer leaves it. It is how sliders and drags are built. Only a pointer with a button down can be captured; capture ends by itself on the last pointerup.

Keyboard and focus

Gamepads

.menu .play { -devcore-nav-down: .menu .settings; }

For a menu driven by arrow keys as well, set view.View.Input.ArrowKeysNavigate = true.

Touch

Taps click. Dragging scrolls with momentum. touch-action says which gestures an element leaves to the page.

Text editing

<input> (text, password, email, number, search…) and <textarea> edit text like Chrome on Windows:

Text on the page can be selected too, unless user-select: none.

Form controls

Buttons, inputs, textareas, checkboxes, radios, ranges and selects look and size like Chrome's on Windows until you style them (see Styling the controls). Bind them to state:

<script lang="cs">
    [State] string name = "";
    [State] bool music = true;
    [State] string quality = "high";
</script>

<input bind:value={name} placeholder="Your name">
<label><input type="checkbox" bind:checked={music}> Music</label>
<select bind:value={quality}>
    <option value="low">Low</option>
    <option value="high">High</option>
</select>

A select opens on press, Alt+Down, F4, Space or the gamepad's confirm button; keys and the d-pad move in its list.

Cursors

The engine draws the cursor that CSS cursor asks for, including image cursors.

Drag and drop

Drag and drop is built from pointer events. The HTML drag-and-drop API (draggable, dragstart, drop) is not implemented.

  1. On pointerdown: SetPointerCapture, remember where the drag started, and mark the item as dragged.
  2. Give the dragged item pointer-events: none and a higher z-index, so the pointer sees what is under it.
  3. On pointermove: move the item with a typed translate, and find the target with ElementFromPoint(x, y)?.Closest(".slot").
  4. On pointerup: find the target the same way, reset the translate, update your state. On pointercancel: put it back.
void Move(PointerEvent e)
{
    var item = (Element)e.CurrentTarget;
    if (!item.HasPointerCapture(e.PointerId)) return;

    item.Style.Set(CssPropertyId.Translate, e.ClientX - startX, e.ClientY - startY, CssUnit.Px);
    var slot = item.OwnerDocument.ElementFromPoint(e.ClientX, e.ClientY)?.Closest(".slot");
    hovered = slot?.GetAttribute("data-slot");
}

The Inventory sample is a complete version of this.