The PrayerRequestForm component provides a compassionate interface for collecting prayer requests with options for anonymous submission and automatic Formspree integration.
Features
- Two-Column Layout: Form on left, informational content on right
- Anonymous Submission: Optional checkbox to submit without sharing name
- Formspree Integration: Sends requests via Formspree API
- Client-Side Validation: Ensures meaningful prayer requests (10+ characters)
- Success State: Shows confirmation message after submission
- Auto-Reset: Form resets after 5 seconds for new submissions
- Progressive Enhancement: Works with or without JavaScript
Installation
import PrayerRequestForm from '../components/PrayerRequestForm.astro';
Basic Usage
From src/pages/index.astro:3:
---
import PrayerRequestForm from '../components/PrayerRequestForm.astro';
---
<PrayerRequestForm />
Props
title
string
default:"Prayer Requests"
Heading text displayed on the right side of the form.
description
string
default:"Share your prayer needs..."
Descriptive text explaining the prayer request process.Default: "Share your prayer needs with our community. We're here to support you in prayer."
Whether to display the anonymous submission checkbox option.
Examples
Default Configuration
Custom Title and Description
<PrayerRequestForm
title="Submit a Prayer Request"
description="Our prayer team is here to support you. Share your needs confidentially."
/>
Without Anonymous Option
<PrayerRequestForm showAnonymous={false} />
Name Field
<input
type="text"
id="prayer-name"
name="name"
placeholder="John Doe"
/>
- Optional by default (when
showAnonymous={true})
- Becomes required when anonymous checkbox is unchecked
- Automatically manages required attribute based on anonymous state
Email Field
<input
type="email"
id="prayer-email"
name="email"
placeholder="[email protected]"
/>
- Always optional
- Used for follow-up communication
- Not required for submission
Prayer Request Field
<textarea
id="prayer-request"
name="request"
required
rows="6"
placeholder="Share your prayer need here..."
></textarea>
- Required field
- Minimum 10 characters (validated client-side)
- 6 rows for comfortable input
- Non-resizable for consistent layout
Anonymous Checkbox
<input
type="checkbox"
id="prayer-anonymous"
name="anonymous"
/>
- When checked: Name field becomes optional
- When unchecked: Name field becomes required
- Shown only if
showAnonymous={true}
Setup
- Create a Formspree account at https://formspree.io
- Create a new form and get your form ID
- Update the action URL in the component:
<form
id="prayer-request-form"
action="https://formspree.io/f/YOUR_FORM_ID_HERE"
method="POST"
>
Submission Process
const response = await fetch(form.action, {
method: 'POST',
body: formData,
headers: {
'Accept': 'application/json'
}
});
Enhanced Payload
The component adds hidden fields for better email organization:
formData.append('_anonymous', anonymous ? 'true' : 'false');
formData.append('_subject', anonymous
? 'Anonymous Prayer Request'
: `Prayer Request from ${name || 'Someone'}`);
Email Subject Examples:
"Prayer Request from John Doe"
"Anonymous Prayer Request"
Validation
Client-side validation ensures quality submissions:
const request = formData.get('request')?.toString().trim();
if (!request || request.length < 10) {
alert('Please provide a meaningful prayer request (at least 10 characters).');
return;
}
Validation Rules:
- Prayer request must be at least 10 characters
- Cannot be empty or whitespace only
- If not anonymous, name should be provided
Success State
After successful submission:
<div id="prayer-success" class="hidden">
<div class="bg-green-50 border border-green-200 rounded-lg p-8 text-center">
<svg class="w-16 h-16 text-green-600 mx-auto mb-4"><!-- Checkmark --></svg>
<h3 class="text-2xl font-semibold text-green-900 mb-2">
Prayer Request Submitted
</h3>
<p class="text-green-700 text-lg">
Thank you for sharing. Our prayer team will be lifting you up in prayer.
</p>
</div>
</div>
- Form is hidden
- Success message appears
- After 5 seconds:
- Form is reset
- Success message is hidden
- Form reappears for new submissions
Two-Column Layout
<div class="grid lg:grid-cols-2 gap-16 items-start">
<!-- Left: Form -->
<div class="bg-gray-50 rounded-2xl p-8">
<form><!-- Form fields --></form>
</div>
<!-- Right: Information -->
<div>
<h2>{title}</h2>
<p>{description}</p>
<!-- Feature highlights -->
</div>
</div>
Responsive Behavior:
- Desktop (
lg and up): Two columns side-by-side
- Mobile: Stacked vertically
Feature Highlights
The right column includes feature cards:
Confidential & Private
<div class="flex items-start gap-3">
<svg class="w-6 h-6 text-brand"><!-- Shield icon --></svg>
<div>
<h3>Confidential & Private</h3>
<p>Your prayer requests are shared only with our dedicated prayer team</p>
</div>
</div>
Prayed Over Daily
<div class="flex items-start gap-3">
<svg class="w-6 h-6 text-brand"><!-- Clock icon --></svg>
<div>
<h3>Prayed Over Daily</h3>
<p>Our prayer team lifts up every request in prayer</p>
</div>
</div>
Anonymous Logic
Dynamic name field requirement based on checkbox:
anonymousCheckbox.addEventListener('change', () => {
if (anonymousCheckbox.checked) {
nameInput.removeAttribute('required');
} else {
nameInput.setAttribute('required', 'required');
}
});
Behavior:
- Checked: Name becomes optional (grayed out label)
- Unchecked: Name becomes required (asterisk shown)
Auto-Reset
Form automatically resets after successful submission:
setTimeout(() => {
form.reset();
form.classList.remove('hidden');
successMessage.classList.add('hidden');
nameInput.setAttribute('required', 'required');
anonymousCheckbox.checked = false;
}, 5000);
Error Handling
try {
const response = await fetch(form.action, {
method: 'POST',
body: formData,
headers: { 'Accept': 'application/json' }
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to submit via Formspree.');
}
// Success handling
} catch (error) {
console.error('Error submitting prayer request:', error);
alert('We encountered an error. Please check your network or contact support.');
}
Loading State
Button shows loading indicator during submission:
// Before submission
submitBtn.disabled = true;
btnText.classList.add('hidden');
btnLoading.classList.remove('hidden');
// After completion (success or error)
submitBtn.disabled = false;
btnText.classList.remove('hidden');
btnLoading.classList.add('hidden');
Button States:
- Default: “Submit Prayer Request”
- Loading: “Submitting…”
- Disabled during submission
Accessibility
- Semantic HTML structure
- Proper label associations
- Focus management
- Keyboard navigation support
- Screen reader friendly
- Clear validation messages
Styling
.prayer-request-section {
font-family: 'Albert Sans', system-ui, sans-serif;
}
Uses Tailwind utility classes:
bg-gray-50: Light gray form background
rounded-2xl: Rounded corners
focus:border-brand: Brand color focus states
transition-colors: Smooth color transitions
Customization
Change Success Message Timing
setTimeout(() => {
// Reset form
}, 10000); // 10 seconds instead of 5
Add Additional Fields
<div>
<label for="prayer-phone">Phone Number (optional)</label>
<input
type="tel"
id="prayer-phone"
name="phone"
/>
</div>
Modify Validation
if (!request || request.length < 20) { // Require 20+ characters
alert('Please provide at least 20 characters.');
return;
}
Add hidden fields for Formspree features:
<input type="hidden" name="_replyto" value="[email protected]" />
<input type="hidden" name="_next" value="https://locc.us/prayer/thanks" />
<input type="hidden" name="_cc" value="[email protected]" />
Testing
- Use Formspree test mode
- Check browser console for errors
- Verify email delivery
- Test anonymous vs. named submissions
Console Testing
// Get form data
const form = document.getElementById('prayer-request-form');
const formData = new FormData(form);
for (let [key, value] of formData.entries()) {
console.log(key, value);
}
Privacy & Security
- HTTPS form submission
- No data stored locally
- Formspree handles email delivery
- Optional anonymous submission
- Clear privacy messaging
Used on:
- Home Page (
/): Main prayer request section