Skip to content

html.input ref .focus() does not work on native #506

Description

@CAMOBAP

Describe the issue

Calling .focus() on a ref attached to html.input or html.textarea does nothing on native. The input is not focused and the keyboard does not appear. The workaround is to call .getNativeRef().focus() instead, which accesses the underlying React Native TextInput directly.

Expected behavior

ref.current.focus() should focus the input and show the keyboard, the same way it works on web.

Steps to reproduce

react-strict-dom version: 0.0.55
Platform: iOS (React Native)

  1. Create an html.input with a ref
  2. Call ref.current.focus() programmatically (e.g. from a button press)
  3. Observe: nothing happens, input is not focused

Root cause: PR #392 replaced explicit method proxying with Object.create(node) + Object.defineProperties(strictRef, Object.getOwnPropertyDescriptors(node)). The old code explicitly proxied focus: proxy(node, 'focus'). The new approach relies on getOwnPropertyDescriptors(node) to copy focus — but focus on a React Native TextInput ref is defined on the prototype chain, not as an own enumerable property, so it is not captured and silently disappears from strictRef.

Workaround:

// broken
ref.current?.focus();

// works
(ref.current as any)?.getNativeRef?.()?.focus?.();

Test case

App.tsx — minimal reproduction
import React, { useRef } from 'react';
import { css, html } from 'react-strict-dom';

export default function App() {
  const inputRef = useRef<HTMLInputElement>(null);

  return (
    <html.div data-layoutconformance="strict" style={styles.container}>
      <html.input ref={inputRef} placeholder="Target input" style={styles.input} />
      <html.button onClick={() => inputRef.current?.focus()} style={styles.button}>
        ref.current.focus() — broken
      </html.button>
      <html.button
        onClick={() => (inputRef.current as any)?.getNativeRef?.()?.focus?.()}
        style={styles.button}
      >
        getNativeRef().focus() — works
      </html.button>
      <html.input placeholder="Tap here to reset focus" style={styles.input} />
    </html.div>
  );
}

const styles = css.create({
  container: {
    paddingTop: 60,
    paddingLeft: 24,
    paddingRight: 24,
    gap: 16,
  },
  input: {
    borderWidth: 1,
    borderStyle: 'solid',
    borderColor: '#999',
    borderRadius: 4,
    padding: 8,
  },
  button: {
    padding: 12,
    borderRadius: 4,
    backgroundColor: '#e0e0e0',
    ':active': { backgroundColor: '#b0b0b0' },
  },
});

Additional comments

Suggested fix — explicitly forward focus and blur for input/textarea strictRefs in useStrictDOMElement.js, similar to how setSelectionRange is currently handled:

const focus = node?.focus;
if (focus) {
  Object.defineProperty(strictRef, 'focus', {
    value: (...args) => focus.call(node, ...args),
    configurable: true,
    writable: true,
  });
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions