A fully configurable, JSON-driven wizard form system for Astro with 10+ field types, comprehensive validation, and keyboard shortcuts.
β¨ JSON-Driven Configuration - No code changes needed to create or modify forms π― 10 Field Types - Single/multi-select, yes/no, text, email, phone, URL, number, name, textarea β¨οΈ Keyboard Shortcuts - A-Z for options, Y/N for yes/no, Enter/Esc/Arrows for navigation β Built-in Validation - Email, URL, phone, number validation out of the box π¨ Customizable Styles - Theme via CSS variables or JSON configuration π Optional CAPTCHA - Support for Cloudflare Turnstile (reCAPTCHA coming soon) π± Responsive - Mobile-first design with touch-friendly interactions βΏ Accessible - Screen reader friendly, keyboard navigable
pnpm add astro-wizard-formsCreate a JSON file with your form structure:
{
"metadata": {
"title": "Contact Form",
"submitButtonText": "Send Message"
},
"profileSelection": {
"label": "How can we help?",
"field": "profileType",
"required": true,
"options": [
{
"value": "support",
"label": "Support",
"description": "Get technical help"
},
{
"value": "sales",
"label": "Sales",
"description": "Product inquiries"
}
]
},
"branches": {
"support": [
{
"field": "issue",
"label": "What's the issue?",
"type": "single-select",
"required": true,
"options": ["Bug", "Question", "Feature Request"]
},
{
"field": "email",
"label": "Your email?",
"type": "email",
"required": true
}
]
}
}---
import formConfig from './form-config.json';
---
<section id="contact-form" class="min-h-screen flex items-center justify-center">
<div class="max-w-2xl w-full">
<div id="form-container">
<!-- Profile Selection -->
<div id="profile-selection" class="space-y-4">
<h2 class="text-3xl font-semibold">{formConfig.profileSelection.label}</h2>
<div class="flex flex-col gap-4">
{formConfig.profileSelection.options.map((option, index) => (
<label class="profile-option cursor-pointer">
<input
type="radio"
name="profileType"
value={option.value}
class="sr-only"
/>
<div class="p-6 border rounded-lg">
<span class="font-semibold">{option.label}</span>
<p class="text-sm text-gray-600">{option.description}</p>
</div>
</label>
))}
</div>
</div>
<!-- Dynamic Form (rendered by JS) -->
<div id="branch-form" class="hidden"></div>
</div>
<!-- Confirmation -->
<div id="confirmation" class="hidden"></div>
</div>
</section>
<script>
import { initWizardForm } from 'astro-wizard-forms';
import formConfig from './form-config.json';
async function handleSubmit(data, captchaToken) {
const response = await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ ...data, captchaToken })
});
const result = await response.json();
return {
success: response.ok,
error: result.error
};
}
initWizardForm({
config: formConfig,
onSubmit: handleSubmit,
enableCaptcha: false, // Optional CAPTCHA
});
</script>@import 'astro-wizard-forms/styles';Or customize with your own styles using the provided CSS classes.
Radio buttons with A-Z keyboard shortcuts.
{
"field": "plan",
"label": "Choose your plan",
"type": "single-select",
"required": true,
"options": ["Free", "Pro", "Enterprise"]
}Checkboxes allowing multiple selections.
{
"field": "features",
"label": "What features do you need?",
"type": "multi-select",
"required": true,
"options": ["Analytics", "API Access", "Custom Domain"]
}Binary choice with Y/N shortcuts.
{
"field": "hasAccount",
"label": "Do you have an account?",
"type": "yes-no",
"required": true
}Single-line text input.
{
"field": "company",
"label": "Company name?",
"type": "text",
"required": true,
"placeholder": "Acme Inc."
}Textarea for longer input.
{
"field": "message",
"label": "Your message",
"type": "multi-line-text",
"required": true,
"placeholder": "Tell us more..."
}Automatic first/last name fields.
{
"field": "name",
"label": "What's your name?",
"type": "name",
"required": true
}Email with validation.
{
"field": "email",
"label": "Your email?",
"type": "email",
"required": true,
"placeholder": "you@example.com"
}International phone format.
{
"field": "phone",
"label": "Phone number?",
"type": "phone",
"required": false,
"placeholder": "+1 234 567 8900"
}URL with http/https validation.
{
"field": "website",
"label": "Your website?",
"type": "url",
"required": false,
"placeholder": "https://example.com"
}Numeric input with min/max.
{
"field": "age",
"label": "Your age?",
"type": "number",
"required": true,
"min": 18,
"max": 120
}- A-Z - Select options (single/multi-select)
- Y/N - Yes/No selection
- Enter (β΅) - Advance to next step
- Escape (Esc) - Go back to previous step
- Arrow Right (β) - Advance (if field filled)
- Arrow Left (β) - Go back
<script>
initWizardForm({
config: formConfig,
onSubmit: handleSubmit,
enableCaptcha: true,
captchaProvider: 'turnstile',
captchaSiteKey: 'your-site-key'
});
</script>Don't forget to add the Turnstile script to your layout:
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>Add country flags to select options:
initWizardForm({
config: formConfig,
onSubmit: handleSubmit,
countryFlags: {
'United States': 'πΊπΈ',
'Canada': 'π¨π¦',
'United Kingdom': 'π¬π§'
}
});:root {
--wizard-bg: linear-gradient(45deg, #667eea, #764ba2);
--wizard-option-bg: #1e1b4b;
--wizard-option-selected: #312e81;
--wizard-text: #ffffff;
}{
"styles": {
"background": "#ffffff",
"optionBackground": "#f3f4f6",
"optionBackgroundSelected": "#3b82f6",
"textColor": "#111827"
}
}Options:
config(required): FormConfig objectonSubmit(required): Async function that handles form submissionenableCaptcha(optional): Enable CAPTCHA (default: false)captchaProvider(optional): 'turnstile' | 'recaptcha' (default: 'turnstile')captchaSiteKey(optional): CAPTCHA site keycountryFlags(optional): Record<string, string> - Country emoji mappings
Returns: void
See the /examples directory for complete working examples:
basic-form-config.json- Simple contact form- Advanced multi-branch form (coming soon)
- Custom styled form (coming soon)
- Astro ^5.0.0
- Modern browser with ES2022 support
MIT
Contributions welcome! Please open an issue or PR.
- GitHub Issues: github.com/jenxi/astro-wizard-forms/issues
- Documentation: github.com/jenxi/astro-wizard-forms