最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

css - How can I keep the virtual keyboard up after a user clicks SEND, which makes an API call? - Stack Overflow

programmeradmin3浏览0评论

I'm creating a web app that involves users sending text in the style of WhatsApp/any messenger app. It is very jarring to have the virtual keyboard disappear every time the user inputs text and presses SEND, so I'd like the keyboard to stay up. However, the SEND button triggers an API call (business logic) which forces focus off the text input.

I've replicated the problem as bare bones as possible in code below.

When we use the following line...

const result = await convertText(userText);

... the virtual keyboard disappears regardless of trying to get the focus instantly back onto the input field.

We can see the desired effect when instead using this hard-coded line:

const result = "Virtual keyboard stays up";

Is there any way to keep the virtual keyboard up the whole time, even when making API calls in the handleSend() method?

I'm using NextJS 15.

REPLICABLE CODE:

'use client';

import { useRef, useState } from "react";

// Mimics an API call to convert text.
async function convertText(text: string): Promise<string> {
  return "CONVERTED:" + text;
}

export default function Test() {
  const [userText, setUserText] = useState('');
  const [convertedText, setConvertedText] = useState('');
  const inputRef = useRef<HTMLInputElement | null>(null);

  /*
   * When we call convertText(), the virtual keyboard disappears every time the
   * user clicks SEND. This is jarring in a messenger-style web app. 
   * When we remove the 'await convertText()' and simply hard code the response, 
   * the 'onMouseDown' and 'inputRef' focus features work as intended.
   */
  const handleSend = async () => {
    const result = await convertText(userText); // Keyboard disappears after every submission.
    // const result = "Virtual keyboard stays up"; // Keyboard stays up after every submission.
    setConvertedText(result);
    inputRef.current?.focus();
  };

  return (
    <div>
      {convertedText}
      <div>
        <input
          ref={inputRef}
          type="text"
          value={userText}
          onChange={(e) => setUserText(e.target.value)}
          placeholder="Enter text"
        />
        <button
          onClick={handleSend}
          onMouseDown={(e) => {
            e.preventDefault();
          }}
        >
          SEND
        </button>
      </div>
    </div>
  );
}```

Thanks in advance.

I'm creating a web app that involves users sending text in the style of WhatsApp/any messenger app. It is very jarring to have the virtual keyboard disappear every time the user inputs text and presses SEND, so I'd like the keyboard to stay up. However, the SEND button triggers an API call (business logic) which forces focus off the text input.

I've replicated the problem as bare bones as possible in code below.

When we use the following line...

const result = await convertText(userText);

... the virtual keyboard disappears regardless of trying to get the focus instantly back onto the input field.

We can see the desired effect when instead using this hard-coded line:

const result = "Virtual keyboard stays up";

Is there any way to keep the virtual keyboard up the whole time, even when making API calls in the handleSend() method?

I'm using NextJS 15.

REPLICABLE CODE:

'use client';

import { useRef, useState } from "react";

// Mimics an API call to convert text.
async function convertText(text: string): Promise<string> {
  return "CONVERTED:" + text;
}

export default function Test() {
  const [userText, setUserText] = useState('');
  const [convertedText, setConvertedText] = useState('');
  const inputRef = useRef<HTMLInputElement | null>(null);

  /*
   * When we call convertText(), the virtual keyboard disappears every time the
   * user clicks SEND. This is jarring in a messenger-style web app. 
   * When we remove the 'await convertText()' and simply hard code the response, 
   * the 'onMouseDown' and 'inputRef' focus features work as intended.
   */
  const handleSend = async () => {
    const result = await convertText(userText); // Keyboard disappears after every submission.
    // const result = "Virtual keyboard stays up"; // Keyboard stays up after every submission.
    setConvertedText(result);
    inputRef.current?.focus();
  };

  return (
    <div>
      {convertedText}
      <div>
        <input
          ref={inputRef}
          type="text"
          value={userText}
          onChange={(e) => setUserText(e.target.value)}
          placeholder="Enter text"
        />
        <button
          onClick={handleSend}
          onMouseDown={(e) => {
            e.preventDefault();
          }}
        >
          SEND
        </button>
      </div>
    </div>
  );
}```

Thanks in advance.
Share Improve this question edited Mar 24 at 8:53 VLAZ 29.1k9 gold badges63 silver badges84 bronze badges asked Mar 24 at 0:03 JamesJames 911 silver badge8 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

The fix was to use a hidden/invisible input that the handleSend() function can focus to immediately:

<input
    ref={hiddenInputRef}
    type="text"
    style={{ position: 'absolute', left: '-9999px', opacity: 0 }}
/>

Then in handleSend() focus on this at the start, and refocus on the original input at the end so the user can continue typing and sending messages:

const handleSend = async () => {
    // Focus immediately on the hidden input.
    hiddenInputRef.current?.focus();
    
    const result = await convertText(userText); 
    setConvertedText(result);
    
    // Refocus on the original input.
    setTimeout(() => {
      inputRef.current?.focus();
    }, 100);
  };

The delay was necessary in my real project.

Here's the full bare bones code:

'use client';

import { useRef, useState } from "react";

// Mimics an API call to convert text.
async function convertText(text: string): Promise<string> {
  return "CONVERTED:" + text;
}

export default function Test() {
  const [userText, setUserText] = useState('');
  const [convertedText, setConvertedText] = useState('');
  const inputRef = useRef<HTMLInputElement | null>(null);
  const hiddenInputRef = useRef<HTMLInputElement | null>(null);

  const handleSend = async () => {
    // Focus immediately on the hidden input.
    hiddenInputRef.current?.focus();
    
    const result = await convertText(userText); 
    setConvertedText(result);
    
    // Refocus on the original input.
    setTimeout(() => {
      inputRef.current?.focus();
    }, 100);
  };

  return (
    <div>
      {convertedText}
      <div>
        {/* Hidden/invisible input used to immediately focus to after submitting a form. */}
        <input
          ref={hiddenInputRef}
          type="text"
          style={{ position: 'absolute', left: '-9999px', opacity: 0 }}
        />
        <input
          ref={inputRef}
          type="text"
          value={userText}
          onChange={(e) => setUserText(e.target.value)}
          placeholder="Enter text"
        />
        <button
          onClick={handleSend}
        >
          SEND
        </button>
      </div>
    </div>
  );
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论