javascriptreactjsoffice-ui-fabricoffice-fabric

How to focus a button in a details list using React and Office Fabric


Anyone have suggestions on how to focus a button in react DetailsList? Refs seem like the way to go, and I'd like to do something like this:

        findDOMNode<HTMLButtonElement>(this.refs.mybutton).focus()

But I haven't been able to get a ref handle on the button element.

One approach I've tried is in my DetailsList:

        <DetailsList
            onRenderItemColumn={this.renderItemColumn}
            ref={(list) => {this.detailsList = list;}}
            ....
        />

And the button I want to focus (coming from renderItemColumn):

                <PrimaryButton
                    onClick={() => this.handleActionSelection(fieldContent)}
                    ariaDescription={buttonText}
                    text={buttonText}
                    ref={"ButtonIWantToFocus"}
                />

In didComponentMount() I can now get access to the DetailList, but I'm not sure how to get the button ref to focus.

Alternatively I can define the button as:

                    <PrimaryButton
                        disabled={true}
                        ariaDescription={buttonText}
                        text={buttonText}
                        ref={(button) => {this.focusButton = button;}}
                    />

This give me a handle to the button, but it has no focus(), function.

Thanks for your ideas.


Solution

  • I think you are not referencing the ref correctly (you don't need findDOMNode).
    After you set and attach your ref to the class instance using the this key word you just reference it using the this key word.

    Here is a small example:

    class App extends React.Component {
    
      focusBtn = () => {
        this.btn.focus();
      };
    
      render() {
        return (
          <div>
            <div onClick={this.focusBtn}>click here to focus the button below</div>
            <hr/>
            <button ref={ref => {this.btn = ref}}>im a button</button>
          </div>
        );
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="root"></div>

    Edit
    Sorry i just noticed you were talking about a component (not just a component but a library component of fabric-ui).
    After doing some reading on their github page i found out you should use the prop componentRef instead of ref.
    Here is the relevant example with fabric-ui:

    class App extends React.Component {
    
      focusBtn = () => {
        this.btn.focus();
      };
    
      render() {
        return (
          <div>
            <div onClick={this.focusBtn}>click here to focus the button below</div>
            <hr/>
            <Fabric.PrimaryButton componentRef={ref => {this.btn = ref}}>im a button</Fabric.PrimaryButton>
          </div>
        );
      }
    }
    
    ReactDOM.render(<App />, document.getElementById("root"));
    button.ms-Button.ms-Button--primary.css-32:focus{
      border: 2px solid red;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.min.css">
    <link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-js/1.4.0/css/fabric.components.min.css">
    <script type="text/javascript" src="//unpkg.com/office-ui-fabric-react/dist/office-ui-fabric-react.min.js"></script>
    <div id="root"></div>