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

I'm creating a web app that involves users sending text in the style of WhatsAppany messenger app

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>
  );
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744265338a4565840.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信