Skip to content

Svelte Forms

Implementing forms in Svelte is highly intuitive due to Svelte’s reactive bindings. Using bind:value, we can link form variables directly and send submissions via the Fetch API asynchronously.


Here is a ready-to-use Svelte component that submits details to Lucid Forms.

<script>
let name = '';
let email = '';
let message = '';
let _honeypot = ''; // Spam trap
let status = 'idle'; // 'idle' | 'loading' | 'success' | 'error'
let errorMessage = '';
async function handleSubmit(event) {
status = 'loading';
errorMessage = '';
// Honeypot bot trap check
if (_honeypot) {
status = 'success';
return;
}
try {
const response = await fetch('https://api.lucidforms.co/f/{your-form-id}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({ name, email, message })
});
const data = await response.json();
if (response.ok) {
status = 'success';
// Reset form variables
name = '';
email = '';
message = '';
} else {
status = 'error';
errorMessage = data.error || 'Form submission failed.';
}
} catch (err) {
status = 'error';
errorMessage = 'A network error occurred. Please try again.';
}
}
</script>
<div class="form-container">
<h2>Contact Us</h2>
{#if status === 'success'}
<div class="alert success">
✓ Thank you! Your message was received.
</div>
{/if}
{#if status === 'error'}
<div class="alert error">
✗ {errorMessage}
</div>
{/if}
<form on:submit|preventDefault={handleSubmit}>
<!-- Invisible Honeypot Field -->
<input type="text" bind:value={_honeypot} class="hidden" tabindex="-1" autocomplete="off" />
<div class="form-group">
<label for="name">Name</label>
<input type="text" id="name" bind:value={name} required />
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="email" id="email" bind:value={email} required />
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" bind:value={message} required rows="4"></textarea>
</div>
<button type="submit" disabled={status === 'loading'}>
{status === 'loading' ? 'Sending...' : 'Send Message'}
</button>
</form>
</div>
<style>
.form-container {
max-width: 400px;
margin: 0 auto;
font-family: sans-serif;
}
.form-group {
margin-bottom: 12px;
}
label {
display: block;
margin-bottom: 4px;
font-weight: bold;
}
input[type="text"],
input[type="email"],
textarea {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.hidden {
display: none;
}
button {
padding: 10px 15px;
background-color: #ff3e00;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:disabled {
opacity: 0.6;
}
.alert {
padding: 10px;
border-radius: 4px;
margin-bottom: 15px;
}
.success {
color: #1b5e20;
background-color: #e8f5e9;
}
.error {
color: #b71c1c;
background-color: #ffebee;
}
</style>