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.

HTML + Waitlister

Trusted by 2,000+
businesses & entrepreneurs

Data Hokage logo
Data Hokage
Fink Academy logo
Fink Academy
stagewise logo
stagewise
Sirius AI logo
Sirius AI
BLADNA logo
BLADNA
PagePal logo
PagePal
ChatAce.io logo
ChatAce.io
Instanote logo
Instanote
DirectoryDeck logo
DirectoryDeck
landman® logo
landman®
datapro logo
datapro
NATRU logo
NATRU
Pop Date logo
Pop Date
Aspire logo
Aspire
WalletX logo
WalletX
quickblogs logo
quickblogs
Data Hokage logo
Data Hokage
Fink Academy logo
Fink Academy
stagewise logo
stagewise
Sirius AI logo
Sirius AI
BLADNA logo
BLADNA
PagePal logo
PagePal
ChatAce.io logo
ChatAce.io
Instanote logo
Instanote
DirectoryDeck logo
DirectoryDeck
landman® logo
landman®
datapro logo
datapro
NATRU logo
NATRU
Pop Date logo
Pop Date
Aspire logo
Aspire
WalletX logo
WalletX
quickblogs logo
quickblogs
“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.”
ReBrain logo
Uliana Korolova
Founder, ReBrain
Use Cases

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.

Example: Single index.html file with waitlist form deployed to GitHub Pages

Learning Projects

Perfect for beginners learning HTML, CSS, and JavaScript. Understand how forms work without framework magic.

Example: Student project building first landing page with email capture

Minimal MVPs

Test ideas quickly without framework overhead. Ship a landing page in minutes, not hours.

Example: Weekend project to validate SaaS idea with 1 HTML file

Portfolio Site Launches

Developers launching personal sites, portfolios, or side projects with zero complexity.

Example: Developer portfolio with "Hire me" waitlist for consulting services

Legacy Site Updates

Add modern waitlist functionality to existing old-school HTML sites without rewriting everything.

Example: Classic HTML site adding pre-order form for new product

Performance-Critical Pages

When page load speed is paramount. No framework bundle = instant load times and perfect Lighthouse scores.

Example: Marketing page that must load in under 100ms globally
Benefits

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.

Choose Your Method

Which integration is
right for you?

Compare both methods to find the best fit for your HTML project

FeatureForm ActionEmbeddable Widget
Setup ComplexityWrite 20 lines JSPaste 2 lines of code
DependenciesZeroZero
Build ToolsNone neededNone needed
Browser SupportAll browsersAll browsers
File Size Impact~0.5KB~2KB
CustomizationComplete controlDashboard only
Best ForLearning & controlQuick 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
Step-by-Step Guide

How to integrate

Follow these HTML-specific instructions

1

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>
Pro tip
Standard HTML5 form with required validation built-in.
2

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;
  }
});
Pro tip
Modern async/await JavaScript. Works in all modern browsers without transpilation.
3

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>
Pro tip
Pure CSS, no preprocessors. Mobile-responsive out of the box.
4

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>
Pro tip
One file, 80 lines, no dependencies. Copy, edit YOUR_WAITLIST_KEY, deploy. Done.
5

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;
}
Pro tip
Pure JavaScript validation. No libraries needed.
6

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 -->
Pro tip
Any form field name gets captured. No special configuration needed.
7

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

Pro tip
No build process = instant deployment. Change one line, re-upload, live immediately.

Need more details?

Check out our complete form action endpoint documentation.

View full documentation
Troubleshooting

Common 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).

FAQ

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.

Explore

More integrations

Explore other platforms

Get started for free

Start collecting sign ups for your product launch in minutes — no coding required.