Add a contact form to Astro
Astro can ship a native HTML form with no client JavaScript, then progressively enhance it when an inline result is useful. The published endpoint stays the same for static and server-rendered output.
Create a free formA copyable example
---
// Contact.astro: this form does not require a server adapter.
---
<form action="https://littlereply.com/api/submit" method="POST" data-littlereply="YOUR_ACCESS_KEY" data-locale="en" data-success="Your message has been received.">
<input type="hidden" name="_fq_key" value="YOUR_ACCESS_KEY" />
<input type="text" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" aria-hidden="true" />
<label for="contact-name">Full name *</label>
<input type="text" name="name" id="contact-name" required />
<label for="contact-email">Email address *</label>
<input type="email" name="email" id="contact-email" required />
<label for="contact-message">Message *</label>
<textarea name="message" id="contact-message" required rows="5"></textarea>
<button type="submit">Send message</button>
<p role="status" aria-live="polite"></p>
</form>
<!-- Accessible AJAX errors and duplicate-safe retries -->
<script src="https://littlereply.com/client/v1.js" data-api="https://littlereply.com" defer></script>The key YOUR_ACCESS_KEY is a placeholder to replace with your form’s public key. The code contains no server key or destination address.
Start with native HTML
Use a POST action, named controls, and the public form key. The fallback remains usable if JavaScript fails or is disabled.
Add a client script only for pending feedback, inline errors, and confirmation without navigation.
Match the published schema
Astro does not change the intake contract. Field names, required values, file ownership, and abuse checks are enforced by the published configuration.
Test the generated site
Verify the built output on the deployed origin. Confirm that scripts load, the form action is HTTPS, and the submission appears before evaluating notification delivery.
Try the template before creating an account
Local preview: changes stay in this browser. No message or email is sent.
HTML contact
Name, email, and message: the essentials for starting a conversation.
LittleReply<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Contact form</title>
<style>form[data-littlereply]{max-width:640px;margin:2rem auto;padding:1.5rem;font:16px/1.6 system-ui,sans-serif;color:#202033;background:white;border:1px solid #e4e4ee;border-radius:16px;box-sizing:border-box}form[data-littlereply] label{display:block;margin-top:1rem;font-weight:600}form[data-littlereply] input,form[data-littlereply] textarea,form[data-littlereply] select{box-sizing:border-box;width:100%;padding:.75rem;font:inherit;border:1px solid #727285;border-radius:8px;background:white;color:#202033}form[data-littlereply] input[type=checkbox],form[data-littlereply] input[type=radio]{width:auto}form[data-littlereply] button{margin-top:1rem;padding:.8rem 1.1rem;font:inherit;font-weight:600;border:0;border-radius:8px;background:var(--form-accent,#4f46e5);color:white;cursor:pointer}form[data-littlereply] :focus-visible{outline:3px solid #f59e0b;outline-offset:3px}form[data-littlereply] button:disabled{opacity:.6}form[data-littlereply] [role=status]{min-height:1.6em}form[data-littlereply] fieldset{border:0;padding:0}form[data-littlereply] .privacy-notice{font-size:.875rem;color:#4b4b60}
form[data-littlereply]{--form-accent:#4f46e5;--form-ink:#ffffff}
form[data-littlereply] button{color:var(--form-ink)}form[data-littlereply] button[data-fq-back]{background:#eee;color:#202033}form[data-littlereply] [hidden]{display:none}</style></head><body>
<form action="https://littlereply.com/api/submit" method="POST" data-littlereply="YOUR_ACCESS_KEY" data-locale="en" data-success="Your message has been stored. We will reply soon.">
<input type="hidden" name="_fq_key" value="YOUR_ACCESS_KEY" />
<input type="text" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" aria-hidden="true" />
<label for="fq_name">Your name *</label>
<input type="text" name="name" id="fq_name" required autocomplete="name" />
<label for="fq_email">Your email address *</label>
<input type="email" name="email" id="fq_email" required autocomplete="email" />
<label for="fq_message">Your message *</label>
<textarea name="message" id="fq_message" required maxlength="5000" rows="5"></textarea>
<button type="submit">Send my message</button>
<p role="status" aria-live="polite"></p>
</form>
<!-- Accessible AJAX errors and duplicate-safe retries -->
<script src="https://littlereply.com/client/v1.js" data-api="https://littlereply.com" defer></script>
</body></html>Replace YOUR_ACCESS_KEY with your form's public key. The code includes its styles and an AJAX enhancement; the native HTML POST also works without JavaScript.
Sources
Frequently asked questions
Does the form need an Astro API route?
No. Native HTML can post directly to the hosted endpoint.
Can I add JavaScript later?
Yes. Progressive enhancement can preserve the working native POST fallback.