Master Code
On The Go

Learn. Practice. Build.

Home › Code Snippets › HTML Snippets › Forms

HTML Snippet

HTML Forms

Every input type, every validation attribute, and the accessibility rules that matter.

Last updated: October 2026

Quick answer: Wrap inputs in a <form> with action and method. Use <label for="id"> paired with <input id="id"> for accessibility. Pick the correct type (email, tel, number, date) for free mobile keyboards and validation. Add required, minlength, and pattern for native validation — no JavaScript needed.

🎬 Live Demo

A working form with native validation. Try submitting with empty fields, invalid emails, or short passwords — the browser enforces the rules.

💡 All validation above is native HTML. No JavaScript was written for the rules.

1

The Basic Form Structure

<form action="/submit" method="POST">
    <label for="name">Full Name</label>
    <input type="text" id="name" name="name" required>

    <label for="email">Email</label>
    <input type="email" id="email" name="email" required>

    <button type="submit">Submit</button>
</form>

Every form needs three things:

  • action — the URL the form submits to.
  • method — GET for search/filters, POST for creating/updating data.
  • name on every input — this is the key sent to the server.
2

Every Input Type You Need

Type Use for Free benefits
text Names, titles, generic text Basic text keyboard
email Email addresses @ keyboard + validation
password Passwords Masked input
number Quantities, ages Numeric keyboard + stepper
tel Phone numbers Dial pad keyboard
url Website addresses .com keyboard + validation
date Birthdays, bookings Native date picker
time Schedules Native time picker
checkbox Multi-select options Native checkbox
radio Single-choice groups Native radio buttons
file Uploads Native file picker
search Search inputs Clear button built-in

💡 Always use the most specific type. type="email" gives you validation and mobile keyboard automatically. Using type="text" for email means reinventing both.

3

Native Validation Attributes

All of these work without a single line of JavaScript:

<!-- Required field -->
<input type="text" required>

<!-- Length constraints -->
<input type="text" minlength="3" maxlength="20">

<!-- Numeric range -->
<input type="number" min="18" max="120">

<!-- Regex pattern -->
<input type="text" pattern="[A-Za-z]{3,}">

<!-- Custom error message -->
<input type="text" required
       title="Please enter your full name">

<!-- Only shown when the field is valid -->
<input type="email">

What each does:

  • required — the field cannot be empty.
  • minlength / maxlength — string length limits.
  • min / max — numeric or date limits.
  • pattern — regex check on the input value.
  • title — custom error message shown by the browser.
4

Accessibility — Labels Are Mandatory

Every input must have a label. There are two ways to associate them:

<!-- Method 1: for + id (preferred) -->
<label for="email">Email address</label>
<input type="email" id="email" name="email">

<!-- Method 2: Wrap the input in the label -->
<label>
    Email address
    <input type="email" name="email">
</label>

<!-- ❌ Wrong — no label, placeholder isn't a label -->
<input type="email" placeholder="Email address">

Placeholders are not labels. Screen readers announce placeholders as content, but they don't identify the field the way a label does. Also, placeholders disappear when the user types — making the field confusing.

Group related inputs with fieldset:

<fieldset>
    <legend>Shipping Address</legend>

    <label for="street">Street</label>
    <input type="text" id="street" name="street">

    <label for="city">City</label>
    <input type="text" id="city" name="city">
</fieldset>
5

Styling Valid, Invalid, and Focus States

CSS pseudo-classes let you style validation state without JavaScript:

/* Default state */
input {
    border: 1px solid #475569;
    padding: 8px 12px;
    border-radius: 6px;
}

/* Focused */
input:focus {
    border-color: #3b82f6;
    outline: none;
    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}

/* Invalid — but only after the user has typed */
input:invalid:not(:placeholder-shown) {
    border-color: #ef4444;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}

/* Valid — but only after typing */
input:valid:not(:placeholder-shown) {
    border-color: #10b981;
}

/* Required but empty */
input:required:placeholder-shown {
    border-color: #475569;
}

💡 Why :not(:placeholder-shown)? Without it, empty required fields get the red border on page load — before the user has done anything. That looks broken. This pseudo-class only applies styles once the user has typed something.

6

A Complete Production Form

<form action="/signup" method="POST" novalidate>
    <fieldset>
        <legend>Create your account</legend>

        <div class="field">
            <label for="name">Full Name</label>
            <input type="text" id="name" name="name"
                   required minlength="2" maxlength="60"
                   autocomplete="name">
        </div>

        <div class="field">
            <label for="email">Email</label>
            <input type="email" id="email" name="email"
                   required autocomplete="email">
        </div>

        <div class="field">
            <label for="password">Password</label>
            <input type="password" id="password" name="password"
                   required minlength="8"
                   autocomplete="new-password"
                   aria-describedby="password-help">
            <small id="password-help">
                At least 8 characters
            </small>
        </div>

        <div class="field">
            <input type="checkbox" id="terms" name="terms" required>
            <label for="terms">I agree to the terms</label>
        </div>

        <button type="submit">Create Account</button>
    </fieldset>
</form>

Key details:

  • autocomplete — helps browsers and password managers fill fields correctly.
  • aria-describedby — connects help text to the input for screen readers.
  • novalidate — disables browser default UI so you can style validation yourself.
  • fieldset + legend — groups related fields with a heading.

🎯 Input Types & Validation Cheatsheet

Attribute Applies to Example
required All inputs, textarea, select <input required>
minlength Text inputs, textarea minlength="8"
maxlength Text inputs, textarea maxlength="100"
min number, date, time, range min="18"
max number, date, time, range max="120"
pattern Text, tel, email, url pattern="[0-9]{3}-[0-9]{4}"
step number, range step="0.01"
autocomplete All inputs autocomplete="email"

⚠️ Common Mistakes

❓ Frequently Asked Questions

How do I create an HTML form?

Use the <form> element with action (the URL to submit to) and method (GET or POST). Inside, add <label> and <input> pairs for each field. Add a submit button with type=submit.

What is native form validation?

Native form validation uses HTML attributes like required, minlength, maxlength, pattern, min, and max to enforce rules in the browser. The browser shows error messages and prevents submission until the form is valid. No JavaScript required.

What input types should I use?

Use email for email addresses, tel for phone numbers, url for URLs, number for numeric input, date for dates, and password for sensitive input. Each type triggers the correct keyboard on mobile and provides native validation.

How do I make forms accessible?

Always associate every input with a <label> using the for attribute. Group related inputs with <fieldset> and <legend>. Use aria-describedby for help text. Test with a screen reader and keyboard navigation.

Should I use GET or POST for form submission?

Use GET for search forms and filters where the data appears in the URL. Use POST for anything that creates, updates, or deletes data, or for sensitive information like passwords and payment details.

🎯 What's Next?

← All HTML Snippets