Disable automatic focusing for a material-ui popover component

I am struggling to create a search match list that updates as the user types in their query. However, I am facing an issue where the input element loses focus to the pop-up. I have attempted to programmatically set the focus using refs, but I am unable to assign a ref to a stateless function component (such as my TextField input).

Here is a demonstration of the problem: https://i.sstatic.net/aWmRL.jpg

You can see in the gif how the pop-up takes focus and hinders further typing by the user.

<TextField
              id='contact'
              label='Contact Name'
              className={classes.textField}
              margin='normal'
              ref={this.nameInput}
              onChange={this.handleContactSearch.bind(this)}
              value={this.state.contactSearch}
            />
            <Popover
              open={Boolean(anchorEl)}
              anchorEl={anchorEl}
              onClick={this.handlePopoverClose}
              anchorOrigin={{
                vertical: 'bottom',
                horizontal: 'center'
              }}
              transformOrigin={{
                vertical: 'top',
                horizontal: 'center'
              }}
              autoFocus={false}
            >
              <List>{this.createContactList()}</List>
            </Popover>

Below are the relevant functions:

  handleContactSearch(event) {
    this.handlePopoverClick(event);
    this.setState({ contactSearch: handleText(event) });
    this.props.filterContacts(
      event.target.value,
      this.props.accountInfo.AccountName
    );
  }
  handlePopoverClick = event => {
    this.setState({
      anchorEl: event.currentTarget
    });
  };

  handlePopoverClose = () => {
    this.setState({
      anchorEl: null
    });
  };

How can I ensure that the TextField element retains focus so that the user can input their query uninterrupted?

Sandbox: https://codesandbox.io/s/mjqoj9lxkj

Answer №1

Try adding the 'disableAutoFocus' and 'disableEnforceFocus' props to your popover component. It did the trick for me!

<Popover
 open={Boolean(anchorEl)}

 // include these props in the popover component
 disableAutoFocus={true}
 disableEnforceFocus={true}
 >

https://material-ui.com/api/modal/

Answer №2

The occurrence of this issue is due to the repeated invocation of this.showPopover(event) whenever the

onChange={this.handleContactSearch.bind(this)}
event is triggered within the <TextField> element.

To resolve this issue, a solution would be to ensure that this.showPopover(event) is called only once.

I managed to address this by utilizing both autoFocus={true} in conjunction with the onFocus={this.showPopover} event on the <TextField/>. However, one downside is that the popover will initially appear empty when opening the modal. To overcome this, I employed a ref on the textfield and implemented a condition to adjust the opacity of the popover so that it only displays when there is content in the textfield.

While perhaps not the definitive solution, this approach is effective and should guide you towards resolving the issue.

<div className={classes.paper}>
    <TextField
        id="contact123"
        label="Contact Name"
        className={classes.textField}
        margin="normal"
        onChange={this.handleContactSearch.bind(this)}
        value={this.state.contactSearch}
        autoFocus={true}
        onFocus={this.showPopover}
        inputRef={input => (this.tf = input)}
    />
    <Popover
        open={Boolean(anchorEl)}
        anchorEl={document.getElementById("contact123")}
        onClick={this.closePopover}
        anchorOrigin={{
            vertical: "bottom",
            horizontal: "center"
        }}
        transformOrigin={{
            vertical: "top",
            horizontal: "center"
        }}
        style={{ opacity: this.tf && !this.tf.value.length ? 0 : 1 }}
    >
        <List>{this.state.contactSearch}</List>
    </Popover>
    <div>
        <Button color="primary" className={classes.saveButton}>
            Save
        </Button>
    </div>
</div>

Sandbox: Live Example

Answer №3

If you're looking for an alternative approach, consider utilizing the Popper, ClickAwayListener, and Backdrop components. By incorporating Popper, you can maintain focus on the input field while still being able to type seamlessly. Here's a rough implementation:

class Foo extends React.Component {
  inputRef = React.createRef(),

  render() {
    const { open, searchValue } = this.state

    <RootRef rootRef={this.inputRef}>
      <div className={classes.container}>
        // You may also consider using TextField
        <FormControl
          onKeyDown={//set open = false}
          onClick={// set open = true (e.g. only when searchValue !== '' }
        >
          <InputBase
            value={searchValue}
            onChange={this.handleSearchValueChange}
            inputRef={this.inputRef}
          />
        </FormControl>
        <Popper anchorEl={this.inputRef.current} open={open} >
          <ClickAwayListener onClick={//set open = false} onClickAway={//set open = false}>
            Popover content
          </ClickAwayListener>
        </Popper>
      </div>
    </RootRef>
  }
}

This is just a demonstration and does not function, but it illustrates how to tackle the challenge of typing in an input field while having a popover/pop-up open.

Answer №4

One way to control the behavior of the popover and search input is by adding onKeyDown and onKeyUp properties respectively. This setup allows the popover to close whenever the user types something and then pops up again when the user stops typing. It may not be the most elegant solution, but it has proven to be effective.

<InputBase
              autoFocus={true}
              value={searchText}
              onChange={(e) => handleSearch(e)}
              onKeyUp={e => setAnchorEl(e.currentTarget)}
              placeholder="Search…"
              classes={{
                root: classes.inputRoot,
                input: classes.inputInput,
              }}
              inputProps={{ "aria-label": "search" }}
            />
            {searchResult && (
              <Popover
              disableAutoFocus 
              className={classes.pop}
              onKeyDown={handleClose}
                id={id}
                open={open}
                anchorEl={anchorEl}
                onClose={handleClose}
                anchorOrigin={{
                  vertical: "bottom",
                  horizontal: "center",
                }}
                transformOrigin={{
                  vertical: "top",
                  horizontal: "center",
                }}
              >
                {searchResult.map((song, i) => {
                  return (
                      <Link to={`/Songs/${song.unique_id}?Artist=${song.artist_id}`}>
                    <ListItem>
                    <IconButton variant="h6" >
                      <PlayCircleFilledRounded/>
                    </IconButton>
                      {song.title}
                      </ListItem>
                      </Link>
                  );
                })}
              </Popover>
            )}
          </div>

Answer №5

The issue I encountered was similar when using the Material-UI <Menu> component. In this instance, the property is referred to as autoFocus.

<Menu autoFocus={false}>
  ...
</Menu>

https://mui.com/material-ui/api/menu/

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

Utilizing MongoDB and Express to access collections within a controller

Is there a way to access the collection in the controller using mongodb and express? I came across this code snippet in the mongodb documentation db.getCollection("countries");, but how do you import the database name: db into a controller? serv ...

Begin the NextJS project by redirecting the user to the Auth0 page without delay

I am new to coding and currently working on a project using Typescript/NextJS with Auth0 integration. The current setup navigates users to a page with a login button that redirects them to the Auth0 authentication page. However, this extra step is unneces ...

Is there a way to display this JSON data using mustache.js without needing to iterate through a

Here is the JSON data: var details = [ { "event": { "name": "txt1", "date": "2011-01-02", "location": "Guangzhou Tianhe Mall" } ...

Uh oh! You haven't set a QueryClient yet. Make sure to use QueryClientProvider to set

My first experience with React Query didn't go as planned when I encountered this error at the beginning of my React app: Even though I added QueryClientProvider to the top of my component tree, I kept getting: Error: No QueryClient set, use QueryCli ...

Setting values and options in Material UI AutoComplete and then assigning the selected value to an object when onChange event occurs - how can it be

I am working on a project where I have a brand object with the field cat_id. When the page loads, categories are loaded into an autocomplete select. My goal now is to set the value of category id as the value for a category option in the autocomplete, an ...

When a table cell is hovered over, a left border will be added

I've been working on adding a left border to the text in a way that highlights the first cell's border when hovering over a row, providing a clear indication of the current row for users. Feel free to check out my progress so far on this fiddle: ...

display rails view using ajax

I have developed a new form that I would like to render using ajax in case it fails validations. In my controller, the code looks like this: def create event = CEvent.new(params[:c_event]) respond_to do |format| if event.save format.html { ...

Guide to presenting JSON data with ajax

I am trying to dynamically display data based on the selected value from a drop-down list using Ajax's GET method. The idea is to modify the URL by appending the selected item in order to retrieve relevant data from the server: Here is an example of ...

Implementing Typescript for managing state in React components

Currently, I have a state set up like this: const [newInvoice, setInvoice] = useState<InvoiceType | null>(invoice) The structure of my InvoiceType is as follows: customer_email: string customer_name: string description: string due_date: stri ...

Using React to simulate API calls outside of testing environments

For instance, I encounter issues when certain endpoints are inaccessible or causing errors, but I still need to continue developing. An example scenario is with a function like UserService.getUsers where I want to use fake data that I can define myself. I ...

In React's contextApi, the this.context object is constantly devoid of any values

sample.js export default class SampleComponent extends React.Component { static contextType= AppProvider; componentDidMount() { console.log('sample',this.context); } render() { return ( <AppConsumer> ...

Dealing with errors while managing asynchronous middleware in Express

I have implemented an asynchronous middleware in express to utilize await for a cleaner code structure. const express = require('express'); const app = express(); app.use(async(req, res, next) => { await authenticate(req); next(); }) ...

Encountering a bug in the comment feature of the next.js npm module

I encountered an issue that is giving the following error messages: 10:03:56.049 ./components/navbar.js 10:03:56.049 13:33 Warning: img elements must have an alt prop, either with meaningful text, or an empty string for decorative images. jsx-a11y/ ...

Error encountered while fetching files from Google Cloud bucket using Firebase functions: RangeError - Maximum call stack size exceeded

I'm currently trying to access Firestore backup files stored in a Google Cloud bucket: export const retrieveFirestoreBackup = functions.https.onCall( async (data: RetrieveFirestoreBackupPayload, context) => { try { return await sto ...

Is it possible to direct the focus to a specific HTML element when the tab key is pressed?

Seeking a solution to shift focus to a button once the user presses the tab key from the currently selected control, while bypassing other dynamic controls in between. The order of controls is as follows: <dynamic drop down control 1> <dynamic d ...

Guide to incorporating third-party JavaScript files and functions into my Angular web app

I have been trying to integrate external code (HTML, JS, and CSS files) into my Angular web application. Within this external code, the structure of the HTML file is as follows: index.html <html> <header> </header> <body> </bo ...

jQuery Datatables have trouble accessing specific row information when the table is set to be responsive

Currently, I'm utilizing the jQuery DataTables plugin along with the responsive addon to dynamically display and hide columns based on the size of the browser window. One of the columns is labeled as Actions, which permits users to edit a record by c ...

What is the best way to make sure flexbox items fill in any available space?

I am currently working on a website project, and I am looking to display text content in two columns using flexbox with each column taking up 50% of the width. However, I am encountering an issue as illustrated in the image below: https://i.sstatic.net/Gh ...

To properly render JSX elements in ReactJS, make sure to enclose adjacent elements within a wrapping tag. If you prefer to use a

Hey, I just started learning React and decided to create a blog. The blog elements are stored in an array and I'm using a map function to display the blog posts. However, when I add something to the map function, I encountered this error: Adjacent JSX ...

What is the process of making circle or square shapes with text inside using React, without the use of SVG images?

Is there a way to create circle and square shapes in React with custom text inside, without relying on SVG images? Check out this example: https://i.sstatic.net/iHZgy.png I attempted the code below but it did not render any shapes: import React from &apos ...