How to use the styled-component property innerRef with a React stateless component?

7.1k Views Asked by At

I have the following styled component:

const Component = styled.div`
    ...
`;

const Button = (props) => {
    return (
        <Component>
            ...
        </Component>
    );
};

export default styled(Button)``;

I want to get a reference to the underlying div of Component. When I do the following I get null:

import Button from './Button.js';

class Foo extends React.Component {

    getRef = () => {
        console.log(this.btn);
    }

    render() {
        return (
            <Button innerRef={elem => this.btn = elem} />
        );
    }
}

Any ideas why I am getting null and any suggestions on how to access the underlying div?

Note: The reason I am doing this export default styled(Button)``; is so that the export styled component can be easily extended.

2

There are 2 best solutions below

0
On

I managed to accomplish this by passing a function down as a prop to the styled-component that I was targeting, then passing the ref back as an argument of the function:

const Component = styled.div`
    ...
`;

const Button = (props) => {
    return (
        <Component innerRef={elem => props.getRef(elem)}>
            ...
        </Component>
    );
};

export default styled(Button)``;

...

import Button from './Button.js';

class Foo extends React.Component {

    getRef = (ref) => {
        console.log(ref);
    }

    render() {
        return (
            <Button getRef={this.getRef} />
        );
    }
}
0
On

Passing a ref prop to a styled component will give you an instance of the StyledComponent wrapper, but not to the underlying DOM node. This is due to how refs work. So it's not possible to call DOM methods, like focus, on styled components wrappers directly.

Thus to get a ref to the actual, wrapped inner DOM node, callback is passed to the innerRef prop as shown in example below to focus the 'input' element wrapped inside Styled component 'Input' on hover.

  const Input = styled.input`
  padding: 0.5em;
  margin: 0.5em;
  color: palevioletred;
  background: papayawhip;
  border: none;
  border-radius: 3px;
`;

class Form extends React.Component {
  render() {
    return (
      <Input
        placeholder="Hover here..."
        innerRef={x => { this.input = x }}
        onMouseEnter={() => this.input.focus()}
      />
    );
  }
}

render(
  <Form />
);

NOTE:- String refs not supported (i.e. innerRef="node"), since they're already deprecated in React.