Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to set focus to React ComboBox component #5299

Closed
1 of 2 tasks
supermonkeybrainz opened this issue Feb 7, 2020 · 14 comments
Closed
1 of 2 tasks

Unable to set focus to React ComboBox component #5299

supermonkeybrainz opened this issue Feb 7, 2020 · 14 comments

Comments

@supermonkeybrainz
Copy link

What package(s) are you using?

  • carbon-components
  • carbon-components-react

Summary

Generally with React we would set focus on a component by getting a ref to the component and calling the focus function on the current ref. Unfortunately, there is no forwardRef and we have no way to get a ref to the input within the ComboBox. I can't seem to figure out a way to inject anything in via props. Is there some way to make this happen?

Relevant information

An example of what I am trying to do:

const Example = () => {
  const [adding, setAdding] = useState(false);
  return (
    <>
      <Button
        onClick={() => {
          setAdding(true);
          // HACK to set focus
          setTimeout(
            () => document.getElementById("test").focus(),
            100 // YMMV *shrug*
          );
        }}
      />

      <ComboBox
        className={classNames({ [styles.hide]: !adding })}
        downshiftProps={{ isOpen: true }}
        id="test"
        onChange={() => setAdding(false)}
        items={[]}
      />
    </>
  )
}

Basically, when the user clicks a Button the ComboBox will show with the dropdown portion visible. I would also like the text input to have focus so the user can start typing right away. You can see I'm using a setTimeout to manually wait for the box to appear so I can set focus to it. Would love some other more reliable method. Suggestions?

@supermonkeybrainz
Copy link
Author

I did find a way around this. You can add the autoFocus property to the ComboBox. I had to tweak the code a bit. Something like the following:

const Example = () => {
  const [adding, setAdding] = useState(false);
  return (
    <>
      <Button onClick={() => setAdding(true)}  />

      {adding && 
        <ComboBox
          autoFocus
          className={classNames({ [styles.hide]: !adding })}
          downshiftProps={{ isOpen: true }}
          id="test"
          onChange={() => setAdding(false)}
          items={[]}
        />
      }
    </>
  )
}

Feels like a hack though, and triggers a11y warnings in eslint (though I'm not sure setting focus programmatically is any better in that regard). Thoughts?

@emyarod
Copy link
Member

emyarod commented Feb 18, 2020

I believe now that we have removed the focus trap dependency we should see the expected behavior (ref #5260)

@supermonkeybrainz
Copy link
Author

I don't believe this has anything to do with focus trap. I want to be able to get a ref to the underlying input element so I can set focus. Am I missing something?

@emyarod
Copy link
Member

emyarod commented Mar 5, 2020

to my understanding it has always been possible to use refs to access the input (e.g. https://ibm.biz/BdqrgR)

the part about the focus trap external dependency was related to focusing on the input, since that library appeared to be stealing focus

@supermonkeybrainz
Copy link
Author

supermonkeybrainz commented Mar 5, 2020

I can't open that link, as I don't have permission or any way to create an account (so far as I can see). However, if you look at the source you will see that the ref to that input is a private class member and not something that I can pass in. What should be happening is that the component should be wrapped in a call to forwardRef (see details here). This way a consumer of the component may pass in their own ref.

If you utilize the forwardRef pattern you could still default to an internal private ref if no ref was passed to the forward. The forwardRef technique is already in place in a number of other components, I just want it added to this one.

Let me know if that doesn't make sense. Thanks!

@asudoh
Copy link
Contributor

asudoh commented Mar 5, 2020

@supermonkeybrainz Are you an IBMer? If so, feel free to write something to our Slack channel and we'll give you the link.

@emyarod
Copy link
Member

emyarod commented Mar 5, 2020

@supermonkeybrainz converted to code sandbox https://codesandbox.io/s/sweet-bush-kkb65

@supermonkeybrainz
Copy link
Author

@asudoh I am not an IBM-er, just an interested user of carbon. :)

@emyarod Thanks for the codesandbox, that clears up what you are trying to say. A creative solution, to be sure. :D

I think the ref solution would be more React-like and straight-forward, but I suppose this will have to do. I do appreciate all the help and responses. Thanks so much!

@supermonkeybrainz
Copy link
Author

supermonkeybrainz commented Mar 6, 2020

Oh wait, that still doesn't fix my issue. I need to set focus to the input programmatically, not handle events from the input. Since I only can access the input through the event.target when the input triggers an event I'm not sure this will solve my problem. Back to the drawing board, I guess.

EDIT: See my original post for the example situation I am dealing with.

@asudoh
Copy link
Contributor

asudoh commented Mar 6, 2020

@supermonkeybrainz You can set a ref to an ancestor node and call .querySelector() to grab a DOM element.

@supermonkeybrainz
Copy link
Author

I will go that route, thanks!

@emyarod
Copy link
Member

emyarod commented Mar 6, 2020

@supermonkeybrainz the sandbox was meant to show ref usage, here it is modified for setting focus https://codesandbox.io/s/agitated-tree-tnioe as a workaround

@supermonkeybrainz
Copy link
Author

Got it, thanks for the example!

@abbeyhrt abbeyhrt self-assigned this Mar 25, 2020
@abbeyhrt
Copy link
Contributor

Closing this since it seems the issue has been addressed. Feel free to let me know if that's not the case!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants