Skip to content

Conversation

@stevegolton
Copy link
Member

@stevegolton stevegolton commented Jan 28, 2026

  • Add GateDetector component that detects when an ancestor Gate opens/closes
  • Use it to autofocus and select the search box when navigating to Settings, Plugins, and Flags pages

Background: The Gate Component

The Gate component is used throughout the UI to wrap pages, tabs, and other content that needs to persist its DOM state when hidden. It works by:

  1. Caching children - When closed, Gate returns the same vnode reference from the previous render, causing Mithril to skip re-rendering that subtree
  2. CSS hiding - Uses display: none to visually hide content while keeping DOM intact
  3. State preservation - Scroll positions, form inputs, and component state persist across page/tab switches

Gate is used in:

  • PageManager - wraps each page so switching pages preserves state
  • Tabs widget - wraps tab content for the same reason
  • DrawerPanel - wraps bottom panel tabs
  • CurrentSelectionTab - wraps selection detail tabs

The Problem

Components inside a Gate can't tell when they become visible vs hidden. The standard Mithril lifecycle hooks (oncreate/onremove) only fire once when the DOM is actually created/destroyed, not when the Gate opens/closes. This makes it impossible to do things like "focus the search box when the user navigates to this page".

The Solution: GateDetector

GateDetector is a wrapper component that:

  1. Finds the closest ancestor Gate via [data-gate-open] attribute
  2. Uses MutationObserver to watch for attribute changes
  3. Fires onVisibilityChanged(visible, dom) when visibility changes (e.g. when the gate opens/closes
  4. Also fires on initial mount if already visible

Usage:

view() {
  return m(GateDetector, {
    onVisibilityChanged: (visible, dom) => {
      if (visible) {
        (dom.querySelector('input') as HTMLInputElement)?.focus();
      }
    }
  }, m('.my-page', ...));
}

Test plan

  • Navigate to Settings page → search box should be focused and selected
  • Navigate away and back → search box should be focused again
  • Same behavior for Plugins and Flags pages
  • Typing in search box should work normally

@github-actions
Copy link

github-actions bot commented Jan 28, 2026

🎨 Perfetto UI Build

✅ UI build is ready: https://storage.googleapis.com/perfetto-ci-artifacts/gh-21443884687-1-ui/ui/index.html

@stevegolton stevegolton enabled auto-merge (squash) January 28, 2026 14:21
Copy link
Contributor

@camillobruni camillobruni left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

{
onVisibilityChanged: (visible: boolean, dom: Element) => {
if (visible) {
const input = findRef(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: would this be worth a common helper on GateDetector or so?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I follow you here..?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean something like GateDetector.focusRef(...) so we don't have to repeat the boilerplate code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack re the boilerplate code. But focusing text inputs by ref is unrelated to GateDetector.

I could get behind a separate utility like focusInputByRef(...) perhaps?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, definitely just nice-to have :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants