HTML
Zero dependencies. Pure HTML, CSS, and JavaScript.
For developers who value simplicity over complexity. No build tools, no npm packages, no framework lock-in. Just clean, performant code that works everywhere. Perfect for static sites, learning projects, and when you want complete control.
Trusted by 2,000+
businesses & entrepreneurs
.png?alt=media&token=939637fa-d391-4d15-85ea-7005e07d08eb)







.png?alt=media&token=264537c9-b2e0-44e7-9d78-3b558d4e10c2)






.png?alt=media&token=939637fa-d391-4d15-85ea-7005e07d08eb)







.png?alt=media&token=264537c9-b2e0-44e7-9d78-3b558d4e10c2)






“I liked how easy it was to set up the waitlist page using already-made templates, but also adjusting colors, fonts, and other parts of the landing page. I also value the functionality of statistics.”

What you can build
Popular ways HTML users implement waitlists
Static Landing Pages
Simple, fast landing pages hosted on GitHub Pages, Netlify, or any static host. No server required.
Learning Projects
Perfect for beginners learning HTML, CSS, and JavaScript. Understand how forms work without framework magic.
Minimal MVPs
Test ideas quickly without framework overhead. Ship a landing page in minutes, not hours.
Portfolio Site Launches
Developers launching personal sites, portfolios, or side projects with zero complexity.
Legacy Site Updates
Add modern waitlist functionality to existing old-school HTML sites without rewriting everything.
Performance-Critical Pages
When page load speed is paramount. No framework bundle = instant load times and perfect Lighthouse scores.
Why Waitlister for HTML?
Built to work seamlessly with HTML's capabilities
Zero Dependencies
No npm install, no package.json, no node_modules. Just HTML, CSS, and JavaScript. No framework version conflicts or breaking changes. Code that lasts forever.
Maximum Performance
No framework overhead. Pages load instantly. Perfect 100/100 Lighthouse scores out of the box. Sub-50KB total page weight including everything.
Universal Compatibility
Works on every browser, every device, every hosting platform. GitHub Pages, Netlify, Vercel, S3, any server. Zero configuration needed.
Complete Control
Full access to every HTML element, CSS property, and JavaScript API. No framework abstractions. Write code exactly how you want it.
Deploy Anywhere
FTP to any server and it works. No build step, no server requirements, no edge functions. Works offline too. Copy one file and you're done.
Learning-Friendly
Understand exactly what's happening. No magic, no hidden complexity. Perfect for learning web fundamentals or teaching others.
Which integration is
right for you?
Compare both methods to find the best fit for your HTML project
Feature | Form Action | Embeddable Widget |
---|---|---|
Setup Complexity | Write 20 lines JS | Paste 2 lines of code |
Dependencies | Zero | Zero |
Build Tools | None needed | None needed |
Browser Support | All browsers | All browsers |
File Size Impact | ~0.5KB | ~2KB |
Customization | Complete control | Dashboard only |
Best For | Learning & control | Quick launches |
Choose Form Action if...
- You want to learn how forms really work
- You need complete control over every detail
- You want to minimize external dependencies
- You're building custom form validation
- You want the lightest possible page weight
- You're teaching web development fundamentals
Choose Embeddable Widget if...
- You want the absolute fastest setup
- You're building a simple landing page
- You prefer managing design in a dashboard
- You want a pre-styled, tested form component
- You're new to JavaScript form handling
How to integrate
Follow these HTML-specific instructions
Create HTML form structure
Build a basic HTML form with email input:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Join Waitlist</title>
</head>
<body>
<form id="waitlist-form">
<input
type="email"
id="email"
name="email"
placeholder="Your email"
required
>
<input
type="text"
id="name"
name="name"
placeholder="Your name (optional)"
>
<button type="submit">Join Waitlist</button>
<div id="message"></div>
</form>
<script src="app.js"></script>
</body>
</html>
Write vanilla JavaScript submission handler
Create app.js
with this code to handle form submission:
// app.js
const WAITLIST_KEY = 'YOUR_WAITLIST_KEY'; // Replace with your key
const API_URL = `https://waitlister.me/s/${WAITLIST_KEY}`;
const form = document.getElementById('waitlist-form');
const message = document.getElementById('message');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const submitBtn = form.querySelector('button');
const originalText = submitBtn.textContent;
// Disable button and show loading state
submitBtn.disabled = true;
submitBtn.textContent = 'Joining...';
message.textContent = '';
// Get form data
const formData = new FormData(form);
const data = new URLSearchParams(formData);
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: data
});
if (response.ok) {
message.textContent = 'Success! You\'re on the list.';
message.style.color = 'green';
form.reset();
} else {
throw new Error('Submission failed');
}
} catch (error) {
message.textContent = 'Error. Please try again.';
message.style.color = 'red';
} finally {
submitBtn.disabled = false;
submitBtn.textContent = originalText;
}
});
Add CSS styling
Style your form with CSS. Here's a complete example:
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
form {
background: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
max-width: 400px;
width: 100%;
}
input {
width: 100%;
padding: 12px 16px;
margin-bottom: 12px;
border: 2px solid #e0e0e0;
border-radius: 6px;
font-size: 16px;
transition: border-color 0.3s;
}
input:focus {
outline: none;
border-color: #667eea;
}
button {
width: 100%;
padding: 14px;
background: #667eea;
color: white;
border: none;
border-radius: 6px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: background 0.3s;
}
button:hover:not(:disabled) {
background: #5568d3;
}
button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
#message {
margin-top: 12px;
text-align: center;
font-weight: 500;
}
</style>
Complete single-file example
Here's everything in one HTML file for maximum simplicity:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Join Our Waitlist</title>
<style>
/* CSS from previous step */
</style>
</head>
<body>
<form id="waitlist-form">
<h2>Join Our Waitlist</h2>
<p>Be the first to know when we launch</p>
<input type="email" id="email" name="email" placeholder="Your email" required>
<input type="text" id="name" name="name" placeholder="Your name (optional)">
<button type="submit">Join Waitlist</button>
<div id="message"></div>
</form>
<script>
const WAITLIST_KEY = 'YOUR_WAITLIST_KEY';
const API_URL = `https://waitlister.me/s/${WAITLIST_KEY}`;
document.getElementById('waitlist-form').addEventListener('submit', async (e) => {
e.preventDefault();
const form = e.target;
const btn = form.querySelector('button');
const msg = document.getElementById('message');
btn.disabled = true;
btn.textContent = 'Joining...';
try {
const data = new URLSearchParams(new FormData(form));
const res = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: data
});
if (res.ok) {
msg.textContent = '✓ Success! You\'re on the list.';
msg.style.color = 'green';
form.reset();
} else {
throw new Error();
}
} catch {
msg.textContent = '✗ Error. Please try again.';
msg.style.color = 'red';
} finally {
btn.disabled = false;
btn.textContent = 'Join Waitlist';
}
});
</script>
</body>
</html>
Add form validation
Add custom validation beyond HTML5 required:
// Add before fetch in the submit handler
const emailInput = document.getElementById('email');
const email = emailInput.value.trim();
// Email validation
if (!email || !email.includes('@') || !email.includes('.')) {
message.textContent = 'Please enter a valid email address';
message.style.color = 'red';
submitBtn.disabled = false;
submitBtn.textContent = originalText;
return;
}
// Optional: Block disposable email domains
const disposableDomains = ['tempmail.com', 'guerrillamail.com'];
const domain = email.split('@')[1];
if (disposableDomains.includes(domain)) {
message.textContent = 'Please use a permanent email address';
message.style.color = 'red';
submitBtn.disabled = false;
submitBtn.textContent = originalText;
return;
}
Add custom fields
Capture additional data beyond email and name:
<!-- Add to your HTML form -->
<input type="text" name="company" placeholder="Company name">
<select name="role">
<option value="">Select your role</option>
<option value="founder">Founder</option>
<option value="developer">Developer</option>
<option value="other">Other</option>
</select>
<textarea name="message" placeholder="Why are you interested?"></textarea>
<!-- All fields are automatically sent to Waitlister -->
<!-- Fields beyond email, name, and phone are saved as custom metadata -->
Deploy and test
Upload to any static host and test:
• Save as index.html
• Test locally: just open file in browser
• Deploy: GitHub Pages, Netlify, Vercel, S3, FTP
• Whitelist your domain in Waitlister settings
• Test form submission end-to-end
Need more details?
Check out our complete form action endpoint documentation.
View full documentationCommon issues & solutions
Quick fixes for HTML-specific problems
Check browser console for errors. Verify WAITLIST_KEY is correct. Make sure you're calling e.preventDefault() on form submit. Check that your domain is whitelisted in Waitlister settings.
Ensure your domain (including localhost for testing) is added to Waitlister's whitelisted domains. For local testing, use a simple local server (python -m http.server or Live Server in VS Code) instead of opening HTML file directly.
fetch() is available in all modern browsers. If you need IE11 support, add a polyfill script before your code: <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/fetch.umd.js"></script>
You forgot e.preventDefault() in your submit handler. This prevents the default form submission behavior that causes page reload.
Make sure you re-enable the button in the finally block so it runs even if there's an error. Use try/catch/finally pattern.
Check your internet connection. Verify the script URL is correct. Check browser Network tab to see if script loads. If behind a firewall, you may need to whitelist waitlister.me domain.
Ensure all form inputs have a name attribute (not just id). FormData uses the name attribute, not id. Check that inputs are inside the <form> element.
Check CSS selectors match your HTML ids/classes. Make sure <style> tag is in <head>. Use browser DevTools to inspect elements and see which styles are applied.
Add your production domain to Waitlister whitelisted domains. Clear browser cache. Check that you uploaded all files. Verify HTTPS is working (mixed content can block API calls).
Common questions
About HTML integration
No! That's the beauty of vanilla HTML/JS. No Node.js, no npm, no package.json, no build tools. Just HTML, CSS, and JavaScript files. Open in a browser and it works.
All modern browsers - Chrome, Firefox, Safari, Edge. The fetch API and async/await work in all browsers from 2017+. For older browser support, add polyfills.
Yes! Perfect for GitHub Pages. Just create an index.html file in your repo, push to GitHub, enable Pages in settings, and you're live. No Jekyll or build process needed.
For the embed method, you can open the HTML file directly. For the form action method with fetch, use a simple local server (python -m http.server or VS Code Live Server) to avoid CORS issues.
You can, but why? Modern vanilla JavaScript is as easy as jQuery and adds zero dependencies. fetch() and querySelector() give you everything jQuery did, but faster and with no library overhead.
Use HTML5 validation (required, type="email", pattern) for basic validation. Add custom JavaScript validation in the submit handler for complex rules. No library needed!
Absolutely! Drag your folder to Netlify for instant deployment. Use Vercel CLI or drag-and-drop. Both support static HTML with zero configuration. It just works.
You don't need TypeScript for simple HTML/JS projects. The code examples work as-is. If you want TypeScript, you'll need a build step, which defeats the simplicity purpose.
You can, but it requires a build process for Tailwind. For true zero-dependency simplicity, use plain CSS. Modern CSS is powerful - grid, flexbox, custom properties. You don't need frameworks.
Either use a CSS-only spinner (lots of free examples on CodePen) or show/hide a loading message by toggling element display. No library needed - just show/hide an element or change button text.
Yes! Static HTML is the most SEO-friendly approach possible. Search engines love simple, fast-loading HTML. Add proper meta tags, heading hierarchy, and semantic HTML for best SEO.
Absolutely! This is the BEST way to learn. Understand how forms, HTTP requests, and browsers really work without framework magic hiding the details. Start simple, add complexity as needed.
Get started for free
Start collecting sign ups for your
product launch in minutes — no coding required.