form
Async form submission with loading states and validation.
Usage
<form data-controller="form"
data-action="submit->form#submit"
data-form-endpoint-value="https://api.web3forms.com/submit">
<input type="hidden" name="access_key" value="YOUR_KEY">
<input type="text" name="name" required>
<input type="email" name="email" required>
<textarea name="message" required></textarea>
<button type="submit" data-form-target="submit">
<span data-form-target="submitText">Send</span>
<span data-form-target="loadingText" class="hidden">Sending...</span>
</button>
<div data-form-target="success" class="hidden">
Message sent successfully!
</div>
<div data-form-target="error" class="hidden">
Something went wrong. Please try again.
</div>
</form>
Targets
| Target | Purpose |
|---|---|
submit |
Submit button (disabled during submission) |
submitText |
Default button text |
loadingText |
Loading state text |
success |
Success message container |
error |
Error message container |
Values
| Value | Type | Description |
|---|---|---|
endpoint |
String | Form submission URL |
Source
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["submit", "submitText", "loadingText", "success", "error"];
static values = { endpoint: String };
async submit(event) {
event.preventDefault();
this.setLoading(true);
this.hideMessages();
try {
const formData = new FormData(this.element);
const response = await fetch(this.endpointValue, {
method: "POST",
body: formData,
});
if (response.ok) {
this.showSuccess();
this.element.reset();
} else {
this.showError();
}
} catch (error) {
this.showError();
} finally {
this.setLoading(false);
}
}
setLoading(loading) {
this.submitTarget.disabled = loading;
this.submitTextTarget.classList.toggle("hidden", loading);
this.loadingTextTarget.classList.toggle("hidden", !loading);
}
hideMessages() {
this.successTarget.classList.add("hidden");
this.errorTarget.classList.add("hidden");
}
showSuccess() {
this.successTarget.classList.remove("hidden");
}
showError() {
this.errorTarget.classList.remove("hidden");
}
}