Guide
HTML Forms
Submit data to 1db using plain HTML and vanilla JavaScript.
The simplest way to integrate 1db is with a standard HTML form and a bit of JavaScript. This approach works with any website, regardless of framework.
Basic Example
Here's a complete, working contact form:
contact.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Contact Form</title>
<style>
* { box-sizing: border-box; }
body {
font-family: system-ui, sans-serif;
max-width: 500px;
margin: 2rem auto;
padding: 0 1rem;
}
.form-group { margin-bottom: 1rem; }
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
input, textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: 6px;
font-size: 1rem;
}
input:focus, textarea:focus {
outline: none;
border-color: #7BAFD4;
box-shadow: 0 0 0 3px rgba(123, 175, 212, 0.2);
}
button {
width: 100%;
background: #7BAFD4;
color: white;
padding: 0.875rem 1.5rem;
border: none;
border-radius: 6px;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
}
button:hover { background: #5a9bc4; }
button:disabled { opacity: 0.6; cursor: not-allowed; }
.error { color: #ef4444; font-size: 0.875rem; margin-top: 0.5rem; }
.success {
background: #10b981;
color: white;
padding: 1rem;
border-radius: 6px;
text-align: center;
}
</style>
</head>
<body>
<h1>Contact Us</h1>
<form id="contact-form">
<div class="form-group">
<label for="name">Name *</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" name="email" required>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea id="message" name="message" rows="4"></textarea>
</div>
<button type="submit">Send Message</button>
<div id="form-error" class="error" style="display: none;"></div>
</form>
<div id="success-message" class="success" style="display: none;">
Thanks! We'll be in touch soon.
</div>
<script>
const API_URL = "https://your-deployment.convex.site/v1/leads";
const API_KEY = "1db_live_YOUR_API_KEY"; // Use a proxy in production!
const form = document.getElementById("contact-form");
const errorDiv = document.getElementById("form-error");
const successDiv = document.getElementById("success-message");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const submitBtn = form.querySelector('button[type="submit"]');
const originalText = submitBtn.textContent;
// Reset state
errorDiv.style.display = "none";
submitBtn.disabled = true;
submitBtn.textContent = "Sending...";
// Gather form data
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
try {
const response = await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
},
body: JSON.stringify({
formSlug: "contact-form", // Your form slug
...data,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || "Submission failed");
}
// Success!
form.style.display = "none";
successDiv.style.display = "block";
} catch (error) {
errorDiv.textContent = error.message || "Something went wrong.";
errorDiv.style.display = "block";
} finally {
submitBtn.disabled = false;
submitBtn.textContent = originalText;
}
});
</script>
</body>
</html>Security Warning
Never expose your API key directly in client-side code on production websites. The example above is fine for testing, but for production you should:
- • Use a server-side proxy to add the API key
- • Use serverless functions (Vercel, Netlify, Cloudflare)
- • Or use our embed widget which handles auth for you
Secure Server Proxy
Here's how to create a simple proxy using serverless functions:
Vercel Edge Function
api/submit.ts
// /api/submit.ts (Vercel Edge Function)
export const config = { runtime: 'edge' };
export default async function handler(request: Request) {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
const body = await request.json();
const { formSlug, ...data } = body;
const response = await fetch(
"https://your-deployment.convex.site/v1/leads",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.ONEDB_API_KEY,
},
body: JSON.stringify({
formSlug: formSlug || "contact-form",
...data,
}),
}
);
const result = await response.json();
return new Response(JSON.stringify(result), {
status: response.status,
headers: { "Content-Type": "application/json" },
});
}Then update your form to use the proxy:
javascript
// Update your form submission
const response = await fetch("/api/submit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
form: "contact-form",
data: formData,
}),
});Client-Side Validation
Add validation before submission for better UX:
javascript
function validateForm(data) {
const errors = {};
if (!data.name || data.name.trim().length < 2) {
errors.name = "Name must be at least 2 characters";
}
if (!data.email || !isValidEmail(data.email)) {
errors.email = "Please enter a valid email";
}
return {
isValid: Object.keys(errors).length === 0,
errors,
};
}
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
// Use in your submit handler:
form.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form);
const data = Object.fromEntries(formData.entries());
const { isValid, errors } = validateForm(data);
if (!isValid) {
// Show errors next to fields
Object.entries(errors).forEach(([field, message]) => {
const errorEl = document.getElementById(`${field}-error`);
if (errorEl) errorEl.textContent = message;
});
return;
}
// Continue with submission...
});