Some checks failed
CI / lint-and-test (push) Has been cancelled
- Enable contact form fields with component IDs - Add callback for Formspree POST with JSON/AJAX - Include honeypot spam protection (_gotcha field) - Handle validation, loading, success/error states - Clear form on successful submission - Add lessons learned documentation Closes #92, #93, #94 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2.6 KiB
2.6 KiB
Sprint 10 - Formspree Integration with Dash Callbacks
Context
Implementing a contact form on a Dash portfolio site that submits to Formspree, a third-party form handling service.
Insights
Formspree AJAX Submission
Formspree supports AJAX submissions (no page redirect) when you:
- POST with
Content-Type: application/json - Include
Accept: application/jsonheader - Send form data as JSON body
This returns a JSON response instead of redirecting to a thank-you page, which is ideal for single-page Dash applications.
Dash Multi-Output Callbacks for Forms
When handling form submission with validation and feedback, use a multi-output callback pattern:
@callback(
Output("feedback-container", "children"), # Success/error alert
Output("submit-button", "loading"), # Button loading state
Output("field-1", "value"), # Clear on success
Output("field-2", "value"), # Clear on success
Output("field-1", "error"), # Field-level errors
Output("field-2", "error"), # Field-level errors
Input("submit-button", "n_clicks"),
State("field-1", "value"),
State("field-2", "value"),
prevent_initial_call=True,
)
Use no_update for outputs you don't want to change (e.g., keep form values on validation error, only clear on success).
Honeypot Spam Protection
Simple and effective bot protection without CAPTCHA:
- Add a hidden text input field (CSS:
position: absolute; left: -9999px) - Set
tabIndex=-1andautoComplete="off"to prevent accidental filling - In callback, check if honeypot has value - if yes, it's a bot
- For bots: return fake success (don't reveal detection)
- For humans: proceed with real submission
Formspree also accepts _gotcha as a honeypot field name in the JSON payload.
Code Pattern
# Honeypot check - bots fill hidden fields
if honeypot_value:
# Fake success - don't let bots know they were caught
return (_create_success_alert(), False, "", "", None, None)
# Real submission for humans
response = requests.post(
FORMSPREE_ENDPOINT,
json=form_data,
headers={"Accept": "application/json", "Content-Type": "application/json"},
timeout=10,
)
Prevention/Best Practices
- Always use
timeoutparameter withrequests.post()to avoid hanging - Wrap external API calls in try/except for network errors
- Return user-friendly error messages, not technical details
- Use DMC's
required=Trueanderrorprops for form validation feedback
Tags
formspree, dash, callbacks, forms, spam-protection, honeypot, ajax, python, requests, validation