What is the best way to remove input focus when clicked away?

I am in the process of developing an application using next js, and I need assistance with designing a search field. The primary functionality I am looking to implement is displaying search suggestions when the user starts typing, but hiding them when the input bar is not in focus.

My challenge arises when trying to show the suggestions again when the user clicks on the input bar. Since the search suggestions contain routes, using onFocus and onBlur events becomes tricky as the element loses focus during a click event, and the route only triggers upon release.

Even after attempting CSS solutions, registering the focus out remains elusive. Is there another approach I could try?

Your help would be greatly appreciated!!

Below is a snippet of my code:

const [suggestionState,setSuggestionState] = useState(false);


<input type="input"
                    
  ref={inputRef}
  autoFocus
  className={styles['search-bar-input']}
  onFocus={()=>{setSuggestionState(true)}}
  onBlur={()=>{setSuggestionState(false)}}
  placeholder="Search Bloggo"
  onChange={(e)=>{

      var trimmedQuery = e.target.value;
      trimmedQuery = trimmedQuery.trim(); 
      setSearchQuery(trimmedQuery);
      getSuggestions(trimmedQuery)

  }}
  onKeyDown={(e)=>{handleKeypress(e)}}

/>
{

searchQuery.length == 0 || suggestionState == false? '':

<div className={styles['search-bar-suggestions']}>
  <Link>... </Link>
</div>
}

Answer №1

You have the option to achieve this using CSS :focus-within

.suggestions {
  display: none;
}

form:focus-within .suggestions {
  display: block;
}

input:focus~.suggestions {
  display: block;
}
<form>
  <input type="input" placeholder="Search Bloggo" value="">
  <div class="suggestions">Suggestions...
    <div><a href="#">Suggestion 1</a></div>
    <div><a href="#">Suggestion 2</a></div>
    <div><a href="#">Suggestion 3</a></div>
    <div><a href="#">Suggestion 4</a></div>
  </div>
</form>


Implementing the above in a React project may look something like this:

import "./styles.css";
import { useState, useEffect } from "react";

export default function App() {
  const [searchQuery, setSearchQuery] = useState("");
  const [results, setResults] = useState([]);

  useEffect(() => {
    if (!searchQuery) {
      setResults([]);
      return;
    }
    fetch(`https://rickandmortyapi.com/api/character/?name=${searchQuery}`)
      .then((response) => response.json())
      .then(({ results }) => setResults(results));
  }, [searchQuery]);

  return (
    <form>
      <input
        value={searchQuery}
        type="input"
        autoFocus
        placeholder="Search Bloggo"
        onChange={(e) => {
          setSearchQuery(e.target.value);
        }}
      />

      {!!results.length && (
        <div className={`suggestions `}>
          <h3>Suggestions</h3>
          {results.map((result) => {
            return (
              <Link key={result.id} url={result.url}>
                {result.name}
              </Link>
            );
          })}
        </div>
      )}
    </form>
  );
}

const Link = ({ url, children }) => (
  <div>
    <a href={url}>{children}</a>
  </div>
);

https://codesandbox.io/s/vigorous-joana-l93oy?fontsize=14&hidenavigation=1&theme=dark

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Save the ID of the list item by wrapping it and storing it in a table cell

I need help with a situation where I have a list of items stored in table cells, and each cell contains a list item. My goal is to save the id of each list item into the cell that contains it. For example: <td><li id='itemID'>content ...

Tips for solving the problem of TSX error where 'ReactNode' cannot be assigned with 'void' type

I've been attempting to loop through the Mui component MenuItem using a forEach loop, but I'm encountering an error stating 'Type 'void' is not assignable to type 'ReactNode''. Here's the section of my code caus ...

Adjust the width of the unordered list to match the width of its widest child element

I'm encountering a minor issue with displaying a ul element as I am just starting to learn CSS. My goal is to set the width of my ul to match the widest listitem it contains. Below is the HTML code I have used: <div id="sidebar"> <ul i ...

Convert checkbox choices to strings stored in an array within an object

I have a intricate object structure JSON{ alpha{ array1[ obj1{}, obj2{} ] } } In addition to array1, I need to include another array: array2 that will only consist of strin ...

Shopping with CommerceJS just got easier with the convenience of using PayPal

Hey there! I'm currently working on an exciting e-commerce project, creating a new store from scratch. However, I've hit a roadblock when it comes to setting up the checkout process. I'm using CommerceJS and integrating PayPal transactions w ...

What is the process for selecting and accessing a DOM element?

Looking to utilize jQuery selector for accessing deep within the DOM. HTML <table> ...more here <tr> <td class="foo bar clickable"> <div> <div class="number">111</div> //Trying to retrieve "111" ...

When typing in the textarea, pressing the return key to create a line break does not function as expected

Whenever I hit the return key to create a new line in my post, it seems to automatically ignore it. For example, if I type 'a' press 'return' and then 'b', it displays 'ab' instead of 'a b'. How can I fi ...

D3.js is providing inaccurate tick numbers

Even though I specify that I want 3 ticks, I end up with 4 in my d3 js code The y-axis values I am working with are [2, 1, 3, 2, 4, 4, 6] svg .select(`[data-labels-y]`) .call(d3.axisLeft().scale(yScale).ticks(3).tickPadding(4))` My expected tick valu ...

Sending requests from a React application to a Node.js backend hosted on an Nginx server with SSL enabled

After creating static files for a reactjs app using the create react app tool, I launched an nginx server on a docker container to serve the front end built with reactjs. This nginx server communicates with a node js in another container. Everything was r ...

Create a Material UI Text Field that has a type of datetime and can span multiple lines

Is it possible to create a Material UI component of type "datetime-local" that can be displayed on multiple lines while still allowing the date to be edited? The issue arises when the width is too narrow and cuts off the date text. Although the TextField ...

What is the process for connecting controls to Canvas sprites?

Any input is EXTREMELY helpful! To put it shortly, I'm in need of assistance with utilizing HTML5/CSS3 buttons to manage sprite animations on my canvas. These buttons are responsible for controlling the direction and speed of the sprites independentl ...

Transferring information from an online platform onto pre-arranged sheets for hard copy

Has anyone had success printing from a website? I have some papers that are already printed with checkboxes. These checkboxes need to be filled in based on information entered through a web form or retrieved from a MySQL database. All of this information ...

Modifying JavaScript object values using the Object() constructor

My background is in Groovy, which has similar syntax to JavaScript. In Groovy, I can easily copy values from one map to another like this: def myMap1 = {}; def myMap2 = {}; myMap1["key1"] = "value1"; myMap1["key2"] = "value2"; myMap1["key3"] = "value3"; ...

Raising css properties using jquery

Is there a way to adjust CSS values using jQuery? I am looking to specifically increase values like top and left, but my current attempt is not producing the desired outcome: var left = 5; $(.object).css("left" + 5); The challenge I am facing is that I ...

The use of dangerouslySetInnerHTML causes the page layout to stretch, expand, or grow in size

I am currently working on my NextJs app, where I'm utilizing CosmicJs as a headless CMS to showcase content on the webpage. Within the layout of my page, I have structured it with 3 columns, and the content pulled from the CMS is meant to be displaye ...

Why am I not seeing my views when trying to export them from a file in my routes folder?

I've been tinkering around with basic routing in ExpressJS and up to this point, I have implemented two routes: app.get('/', function(req,res) { res.render('index'); }); app.get('/pics', function(req,res) { res.rend ...

JavaScript function to add or subtract

I need to include additional inputs for "+ and -" 60mm and 120mm in my function. How can I achieve this without turning all of them into separate functions? <template> <card class="card"> <h2>Measurement</h2> <form&g ...

Tips for eliminating the domain name from the src URL attribute using Jquery

Is there a way to extract the img src attribute and retrieve only the image path without the domain name included? var imgurl = "http://nitseditor.dev/img/home/bg.jpg"; For instance, I would like to display img/home/bg.jpg instead of the full URL. Any id ...

The upcoming development server will exclusively deliver HTML content without scripts or assets, mirroring the setup of the standard create-next-app template

In an attempt to recreate the problem I am facing, I decided to start by setting up a new Next.js app template folder using the command npx create-next-app (Version 13.1.6==latest, all default options, Node v18.14.0==LTS). However, when I try to run the pr ...

Dynamic routing in Next.js expands upon the current path

With my Next.js blog utilizing Strapi CMS, I am attempting to arrange the posts by their respective categories. I have set up a dynamic route for categories [id].js and have implemented getStaticPaths as shown below: export async function getStaticPaths() ...