Creating an HTML form with the submit button outside the form is an unconventional but achievable task. This approach can be useful in certain design scenarios such as when you want to customize the layout or functionality of the submit button independently from the form.
Key Takeaway
- Create a form with all the fields you need. Create a button outside the form.
- Add an id to the form to identify it.
- Reference the form in the button as shown below.
<form id="myForm">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<!-- Add more form controls as needed -->
</form>
<button form="myForm" type="button" >Submit</button>
Here is a good scenario of when this would be useful.
I was working on a react app and I wanted to have one button to reveal the hidden form as well as submit the forms data to the backend . This means I had to use condition rendering for the button. This way, when I click the button the first time, it shows the form and when I click it the second time, it submits the data to the backend.
Essentially, I still need two buttons which will be rendered depending on the state of the button.
Now that you understand what I was trying to achieve, Here's a step-by-step guide on how to create an HTML form with the submit button outside the form:
Prerequisites
For this tutorial, we'll use a sample code snippet that includes a form designed for becoming an instructor on a platform. The key elements include:
- A form with inputs for business name, account number, and bank.
- A submit button that is initially outside the form.
- An understanding of React
I have used bootstrap for the styling and antd for the icons. so make sure they are imported in your project. In the end, you will have the whole code if you get confused in between. You can then tweak the code to your needs.
Step 1: Creating the HTML structure
If you are using VSCODE as your code editor, you can generate this boilerplate by typing the !
symbol then press the tab
key.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Become an Instructor</title>
</head>
<body>
<!-- Your content will go here -->
</body>
</html>
Step 2: Form Setup
What makes it possible to have the button outside the form is giving your form an identify (preferably an id) that the button will use to know which form to reference.
Within the body tag, create the form element. In our example, the form has a unique identifier my-form
.
<form id='my-form' onSubmit={handleSubmit}>
<!-- Form controls will be added here -->
</form>
Step 3: Form Controls
Inside the form, add the necessary form controls as shown in the code below. These include text inputs for business name, account number, and bank.
<input type="text" placeholder="Enter Business Name" required class="form-control mb-4 p-4" value={bizname} onChange={e => setBizname(e.target.value)} />
<input type="text" placeholder="Enter Account Number" required class="form-control mb-4 p-4" value={accNumber} onChange={e => setAccNumber(e.target.value)} />
<input type="text" placeholder="Enter Bank Name" required class="form-control mb-4 p-4" value={bank} onChange={e => setBank(e.target.value)} />
Step 4: External Submission Button
Now, create the submit button outside the form. This button will trigger the form submission.
<button form='my-form' disabled={!bizname || !accNumber || !bank || loading} type="submit" class="form-control btn btn-lg btn-primary">
{loading ? < SyncOutlined spin /> : "Submit"}
</button>
Step 5: Create the Unhide button
Create another button below this one, to be used for the form unhiding. Below is the button.
<Button className='mb-3' type='primary' block shape='round' icon={loading ? <LoadingOutlined /> : <SettingOutlined />} size="large" onClick={becomeInstructor} disabled={user && user.role && user.role.includes("instructor") || loading}>
{loading ? "Processing..." : "Payout Setup"}
</Button>
This is how your code should look like right now:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Become an Instructor</title>
</head>
<body>
<form id='my-form' onSubmit={handleSubmit}>
<input type="text" placeholder="Enter Business Name" required class="form-control mb-4 p-4" value={bizname} onChange={e => setBizname(e.target.value)} />
<input type="text" placeholder="Enter Account Number" required class="form-control mb-4 p-4" value={accNumber} onChange={e => setAccNumber(e.target.value)} />
<input type="text" placeholder="Enter Bank Name" required class="form-control mb-4 p-4" value={bank} onChange={e => setBank(e.target.value)} />
</form>
<!------ Button 2 ----->
<button form='my-form' disabled={!bizname || !accNumber || !bank || loading} type="submit" class="form-control btn btn-lg btn-primary">
{loading ? < SyncOutlined spin /> : "Submit"}
</button>
<!----- Button 2 ----->
<Button className='mb-3' type='primary' block shape='round' icon={loading ? <LoadingOutlined /> : <SettingOutlined />} size="large" onClick={becomeInstructor} disabled={user && user.role && user.role.includes("instructor") || loading}>
{loading ? "Processing..." : "Payout Setup"}
</Button>
</body>
</html>
Step 6: Add Logic to the Buttons
We are going to make some changes to the whole document so that we are able to add logic. For this to be possible, JSX is involved so that you cannot write JavaScript in a html document.
-
The first change is changing the file extension to
.jsx
rather than.html
. -
We also need to add logic to the buttons. Here is the logic for the buttons.
{hidden ? ( <button className='mb-3' type='primary' block shape='round' icon={loading ? <LoadingOutlined /> : <SettingOutlined />} size="large" onClick={becomeInstructor} disabled={user && user.role && user.role.includes("instructor") || loading}> {loading ? "Processing..." : "Payout Setup"} </button>) : (<button form='my-form' disabled={!bizname || !accNumber || !bank || loading} type="submit" className="form-control btn btn-lg btn-primary"> {loading ? < SyncOutlined spin /> : "Submit"} </button>)}
In this code, I am using the ternary operator
{hidden ? (first block) : (second block)}
a shorthand for anif-else
statement.If
hidden
istrue
, it renders the first block of JSX inside the parentheses; otherwise, it renders the second block. -
The next step is to handle the click functionality of the buttons. The first button requires that when it is clicked, the function becomeInstructor is called to unhide the form. While the second requires that when it is clicked, it handles form submision. Below is the code for both functions.
const becomeInstructor = () => { setHidden(false); }; const handleSubmit = async (e) => { e.preventDefault(); try { const response = await axios.post("/api/make-instructor", { user, bizname, accNumber, bank }); } catch (err) { console.log("An error occurred", err); } }
Ensure that
axios
is installed in your project. -
Now let's put the code together. React works with components. So we need to create a component that will hold the handler function as well as return the html code. In this example I will call my component
BecomeInstructor
const BecomeInstructor = () => { The whole code goes here. }
-
Here is the whole code so far.
const BecomeInstructor = () => { const becomeInstructor = () => { setHidden(false); }; const handleSubmit = async (e) => { e.preventDefault(); try { const response = await axios.post("/api/make-instructor", { user, bizname, accNumber, bank }); } catch (err) { console.log("An error occurred", err); } } return ( <> <body> <form id='my-form' onSubmit={handleSubmit}> <input type="text" placeholder="Enter Business Name" required class="form-control mb-4 p-4" value={bizname} onChange={e => setBizname(e.target.value)} /> <input type="text" placeholder="Enter Account Number" required class="form-control mb-4 p-4" value={accNumber} onChange={e => setAccNumber(e.target.value)} /> <input type="text" placeholder="Enter Bank Name" required class="form-control mb-4 p-4" value={bank} onChange={e => setBank(e.target.value)} /> </form> <!------ Button 2 -----> <button form='my-form' disabled={!bizname || !accNumber || !bank || loading} type="submit" class="form-control btn btn-lg btn-primary"> {loading ? < SyncOutlined spin /> : "Submit"} </button> <!----- Button 2 -----> <Button className='mb-3' type='primary' block shape='round' icon={loading ? <LoadingOutlined /> : <SettingOutlined />} size="large" onClick={becomeInstructor} disabled={user && user.role && user.role.includes("instructor") || loading}> {loading ? "Processing..." : "Payout Setup"} </Button> </> ) } export default BecomeInstructor;
-
The only thing remaining now is to import all the dependencies used in the project. Add them at the top of the document. Here are all the dependencies used.
import React from 'react' import axios from "axios"; import { Button } from "antd"; import { SettingOutlined, UserSwitchOutlined, LoadingOutlined } from "@ant-design/icons"; import { toast } from "react-toastify"; import { useRouter } from 'next/router';
This project will now use one button to show the form and submit the data to the backend.
That was a pretty long explainer. If you wanna see more of these, let me know in the comments section.
Conclusion
Creating an HTML form with the submit button outside the form provides flexibility in design. By following the steps outlined in this tutorial and using the provided code snippet, you can implement this unconventional yet practical approach in your web development projects. Customize the code further based on your specific requirements and integrate it seamlessly into your platform.
If you want a detailed explanation of the functionality let me know down in the comments.
If you read so far, thank you for reading and I wish you success in your coding journey.
Thank you : )