Skip to content

Android 16 – HTML5 builds lose input after external UI interaction due to window.focus() in template #883

@AleCGames

Description

@AleCGames

We are experiencing a focus/input issue in HTML5 builds generated by Solar2D when running on Android 16 (modern mobile browsers).

After extensive testing, the problem appears to be caused by the default focus-handling code appended to index.html by Solar2D:

<script>
  window.addEventListener('load', function(){ window.focus() });
  window.addEventListener('mousedown', function () {
    document.activeElement.blur();
    window.focus();
  }, true);
</script>

Problem Summary

On modern mobile browsers (tested on Android 16), forcing window.focus() — especially combined with document.activeElement.blur() — can break input handling after the game loses focus due to interaction with external UI elements.

Scenario

  1. The HTML5 game runs embedded inside a platform that injects UI elements outside the canvas (e.g., status bar, overlay controls, exit button, etc.).
  2. The user taps one of those external UI elements.
  3. The browser correctly shifts focus away from the canvas.
  4. The user taps the canvas again to resume gameplay.

Expected behavior:
The game should regain focus and continue receiving input normally.

Actual behavior:
The canvas stops receiving input events permanently.
The game appears frozen and cannot recover, regardless of further taps.

The issue is 100% reproducible in embedded environments such as YouTube Playables on Android 16.

Root Cause (Suspected)

Modern mobile browsers heavily restrict window.focus() and focus manipulation unless triggered by trusted user gestures.

The current template:

  • Forces window.focus() on load
  • Blurs document.activeElement
  • Forces window.focus() again on every mousedown

This appears to interfere with the browser’s focus lifecycle after external UI interactions, leaving the page in an inconsistent focus state.

In short:
window.focus() is no longer reliable behavior in modern mobile environments.

Proposed Fix

Instead of managing focus at the window level, focus management should be limited to the canvas element itself, and only in response to real user interaction.

Replacing the default logic with canvas-based focus handling resolves the issue completely:

<script>
  const canvas = document.getElementById('canvas');

  // Allow canvas to receive focus
  canvas.tabIndex = 0;

  // Focus on load
  window.addEventListener('load', () => {
    canvas.focus();
  });

  // Refocus only on real user interaction with the canvas
  canvas.addEventListener('pointerdown', () => {
    canvas.focus();
  });
</script>

Why this works

  • No forced window.focus()
  • No aggressive blur() calls
  • Focus changes occur only on legitimate user interaction
  • Compatible with modern mobile browser restrictions
  • Fully fixes the freeze after external UI interaction

After this change:

  • Interacting with external UI elements does NOT permanently break input
  • Tapping the canvas restores gameplay reliably
  • No freezes observed

Suggested Action

Consider updating the default HTML5 template to:

Remove window.focus() calls
Remove global blur() logic
Handle focus strictly at the canvas level
Tie focus restoration to trusted pointer events

This approach appears to be safer and more future-proof for modern mobile browsers and embedded environments.

Environment

  • Solar2D: HTML5 build
  • Platform: Android 16
  • Browser: Modern mobile Chromium-based browser
  • Reproducible in: Embedded environments (e.g., YouTube Playables)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions