60

I have a form in one of my React components, and and in the outside component that calls it I want to pass a reference to a button there, so that I can also submit that using that button.

To make it more clear I have the following:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class CustomForm extends Component {
  render() {
    return (
      <form onSubmit={alert('Form submitted!')}>
        <button type='submit'>Inside Custom</button>
      </form>
    );
  }
}

function App() {
  return (
    <div>
      <CustomForm />
      <button>In Root</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Now, I can submit the form using the button titled 'Inside Custom', but I also want to be able to submit the form using the button titled 'In Root' that is located in the root component. Is there a way to somehow pass reference from that button to that custom component, and actually submit the form when In Root button is clicked?

2

7 Answers 7

178

You can achieve this by using regular HTML capabilities (HTML form Attribute), no need to use the React hacks:

Add "id" attribute to your form: id='my-form'

class CustomForm extends Component {
    render() {
        return (
             <form id='my-form' onSubmit={alert('Form submitted!')}>
                // Form Inputs go here    
             </form>
        );
    }
}

Then add the same Id to the "form" attribute of the target button outside of the form:

<button form='my-form' type="submit">Outside Button</button>

Now, the 'Outside Button' button will be absolutely equivalent as if it is inside the form.

Note: This is not supported by IE11.

Sign up to request clarification or add additional context in comments.

3 Comments

Do you know any way we can make this work in IE11? @pubudu
@Vidur unfortunately no. I strongly recommend the solution which suggests passing handleSubmit as a prop from the parent for you. This solution will even work for older browsers like IE8
is this a better way?
11

Edit: Simple and correct answer: https://stackoverflow.com/a/53573760/5271656

In React, data flows down and actions flow up. So notify child component about button click in the parent.
This is how you can do this.

import React, { Component } from "react";
import ReactDOM from "react-dom";

class CustomForm extends Component {
  handleOnSubmit = e => {
    e.preventDefault();
    // pass form data
    // get it from state
    const formData = {};
    this.finallySubmit(formData);
  };

  finallySubmit = formData => {
    alert("Form submitted!");
  };

  componentDidUpdate(prevProps, prevState) {
    if (this.props.submitFromOutside) {
      // pass form data
      // get it from state
      const formData = {};
      this.finallySubmit();
    }
  }

  render() {
    return (
      <form onSubmit={this.handleOnSubmit}>
        <button type="submit">Inside Custom</button>
      </form>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      submitFromOutside: false
    };
  }
  submitCustomForm = () => {
    this.setState({
      submitFromOutside: true
    });
  };

  componentDidMount() {
    console.log(this.form);
  }

  render() {
    return (
      <div>
        <CustomForm submitFromOutside={this.state.submitFromOutside} />
        <button onClick={this.submitCustomForm}>In Root</button>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);  

To me, this solution is hacky and not in a react way but serves your use-case.
Find working solution here:https://codesandbox.io/s/r52xll420m

3 Comments

BTW, why do you say it's not a react way and is a hacky solution?
but i didn't get why you want to have submit functionality inside CustomForm component, so why you can't simply make it in App component and pass as a prop to Custom form component?
@BhojendraRauniyar the correct way would have been to pass a function to child and child would call that on submit. But to answer OP's use-case that's the only solution I can think of. ref can also be used but that would require sending form values to parent
5

Well, set up a button with type of submit and attribute form which has value equal to id of the form you want to submit

Comments

2

You can set in the state a flag propery for example rootBtnClicked: false and a method that handles the click in the App component. Also in the <CustomForm />, add a prop e.g. rootBtnClicked={this.state.rootBtnClicked}. When "In Root" button is clicked, trigger that method; then the method changes the state with setState(). Then inside the CustomForm component's render() method, check if the prop is true. If it is, manually trigger .submit() using React's ref.

1 Comment

You can try to provide a code sample when you answer questions. Just saying, it can help people better understand what you mean.
0

You can pass the submit function as a prop and use this method whenever you want. for more complex situations you can use redux save your form data on redux and whenever the button is clicked you read data from redux and submit them

Comments

0

None of these solutions worked for me, but I finally figured it out by doing

document.forms[0].submit()

Since there was only one form on the page, I selected it with the 0 index, but if there are multiple forms then you'd need to use the applicable index for the forms array.

1 Comment

why you are using document? I think one purpose of using react to avoid accessing DOM element like this
-2

You can pass the onSubmit click handler as a props as follows:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class CustomForm extends Component {

  render() {
    return (
      <form onSubmit={this.props.handleSubmit}>
        <button type='submit'>Inside Custom</button>
      </form>
    );
  }
}

function App() {
 handleSubmit = () => {
   alert('Form submitted!')
}
  return (
    <div>
      <CustomForm onSubmit={this.handleSubmit} />
      <button>In Root</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Passing function as a props to handle form submit makes the CustomForm element more reusable since the business logic for the submit is not part of CustomForm component.

3 Comments

This not what OP wants. In your solution button in App component does not call form submit in CustomForm
@MurliPrajapati Ah, I see it, I actually went React way of doing the same, thanks for pointing.
The Submit button has to be outside the Form. Thus, this answer doesn't contributes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.