Basic Form

Accessible form pattern using the form-field custom element. Native HTML5 validation with CSS-only feedback states.

Overview

This snippet provides a complete contact form with all common input types. It uses form.stacked for vertical layout, <form-field> for validated inputs, and semantic elements like <fieldset> and <footer> instead of wrapper divs.

Key features:

  • Zero wrapper <div> tags — every element is semantic or custom
  • Native HTML5 validation (no JavaScript required)
  • Accessible labels and helper text
  • Consistent field styling via <form-field>
  • Proper autocomplete attributes
  • Checkbox and radio group patterns
  • Form actions via footer.actions.end

Live Example

A contact form with text inputs, select, textarea, checkbox, and radio buttons.

Source Code

The form.stacked class provides vertical layout. Each validated field uses <form-field>; optional controls use bare semantic elements.

<form action="/submit" method="POST" class="stacked"> <h2>Contact Form</h2> <!-- Text input with required validation --> <form-field> <label for="name">Full Name</label> <input type="text" id="name" name="name" required autocomplete="name" placeholder="John Doe" aria-describedby="name-msg" > <output id="name-msg" for="name" aria-live="polite"> Enter your full name as it appears on official documents. </output> </form-field> <!-- Email input with type validation --> <form-field> <label for="email">Email Address</label> <input type="email" id="email" name="email" required autocomplete="email" placeholder="john@example.com" aria-describedby="email-msg" > <output id="email-msg" for="email" aria-live="polite"> We'll never share your email with anyone else. </output> </form-field> <!-- Select dropdown --> <form-field> <label for="subject">Subject</label> <select id="subject" name="subject" required> <option value="">Select a topic...</option> <option value="general">General Inquiry</option> <option value="support">Technical Support</option> <option value="sales">Sales Question</option> <option value="feedback">Feedback</option> </select> </form-field> <!-- Textarea with minlength --> <form-field> <label for="message">Message</label> <textarea id="message" name="message" rows="5" required minlength="20" placeholder="Tell us what's on your mind..." aria-describedby="message-msg" ></textarea> <output id="message-msg" for="message" aria-live="polite"> Minimum 20 characters. </output> </form-field> <!-- Optional checkbox — no form-field needed --> <label> <input type="checkbox" name="newsletter" value="yes"> Subscribe to our newsletter </label> <!-- Radio group — fieldset.minimal.group replaces inner div --> <fieldset class="minimal group"> <legend>Preferred contact method</legend> <label> <input type="radio" name="contact-method" value="email" checked> Email </label> <label> <input type="radio" name="contact-method" value="phone"> Phone </label> </fieldset> <!-- Form actions — semantic footer replaces div --> <footer class="actions end"> <button type="reset" class="secondary">Reset</button> <button type="submit">Send Message</button> </footer> </form>

Field Types

Text Input

Standard text input with label, placeholder, and helper text.

<form-field> <label for="name">Full Name</label> <input type="text" id="name" name="name" required aria-describedby="name-msg"> <output id="name-msg" for="name" aria-live="polite">Helper text goes here.</output> </form-field>

Select Dropdown

Native select with placeholder option.

<form-field> <label for="subject">Subject</label> <select id="subject" name="subject" required> <option value="">Select a topic...</option> <option value="general">General Inquiry</option> </select> </form-field>

Checkbox

Optional checkbox — bare <label> is sufficient when no validation or helper text is needed.

<label> <input type="checkbox" name="newsletter" value="yes"> Subscribe to our newsletter </label>

Radio Group

Radio buttons grouped in a fieldset.minimal.group — removes border/padding and stacks children with flex column. No inner <div> needed.

<fieldset class="minimal group"> <legend>Preferred contact method</legend> <label> <input type="radio" name="contact-method" value="email" checked> Email </label> <label> <input type="radio" name="contact-method" value="phone"> Phone </label> </fieldset>

Usage Notes

  • Labels: Every input must have an associated label with matching for/id attributes
  • Autocomplete: Use appropriate autocomplete values to help browsers autofill
  • Validation: Use native attributes like required, minlength, pattern, and type
  • Helper text: Use <output> with aria-describedby and aria-live="polite" for accessible hints
  • Grouping: Use <fieldset> and <legend> for radio/checkbox groups
  • Actions: Use footer.actions.end for right-aligned submit/reset buttons

Related

Form Field

Form field element documentation

Input Element

Native input element patterns

Form Element

Native form element documentation