Skip to main content

Forms Component

Complete form styling system with validation states, floating labels, and responsive layouts

Overview

The Forms component provides a comprehensive styling system for all form elements. It includes modern form controls, validation states, floating labels, inline forms, responsive layouts, and accessibility features. The component maintains consistency across all input types while providing flexibility for different use cases.

📝 Complete Form Controls

Styling for all input types, select, textarea, checkboxes, radios, and file inputs.

✅ Validation States

Built-in validation styling with success, error states, and feedback messages.

🏷️ Floating Labels

Modern floating label inputs for improved user experience and space efficiency.

📐 Flexible Layouts

Inline forms, aiab-grid layouts, responsive designs, and form grouping options.

♿ Full Accessibility

Proper focus management, ARIA attributes, and screen reader support.

🎨 Customizable Styling

CSS variables for easy theming and consistent design across all form elements.

Basic Form Elements

Text Inputs

Text Input Types
<div class="aiab-form-group">
  <label for="text-input">Text Input</label>
  <input type="text" id="text-input" class="aiab-form-control" placeholder="Enter text here">
</div>

<div class="aiab-form-group">
  <label for="email-input">Email Input</label>
  <input type="email" id="email-input" class="aiab-form-control" placeholder="user@example.com">
</div>

<div class="aiab-form-group">
  <label for="password-input">Password Input</label>
  <input type="password" id="password-input" class="aiab-form-control" placeholder="Enter password">
</div>

Select and Textarea

Select Dropdown and Textarea
<div class="aiab-form-group">
  <label for="select-input">Select Dropdown</label>
  <select id="select-input" class="aiab-form-control">
    <option value="">Choose an option</option>
    <option value="option1">Option 1</option>
    <option value="option2">Option 2</option>
  </select>
</div>

<div class="aiab-form-group">
  <label for="textarea-input">Textarea</label>
  <textarea id="textarea-input" class="aiab-form-control" rows="4" placeholder="Enter your message..."></textarea>
</div>

Checkboxes and Radio Buttons

Checkbox and Radio Examples

Checkboxes

Radio Buttons

Inline Checkboxes and Radios

<!-- Standard Checkboxes -->
<div class="aiab-form-check">
  <input type="checkbox" id="check1" class="aiab-form-check-input">
  <label for="check1" class="aiab-form-check-label">Default checkbox</label>
</div>

<!-- Radio Buttons -->
<div class="aiab-form-check">
  <input type="radio" id="radio1" name="radioGroup" class="aiab-form-check-input">
  <label for="radio1" class="aiab-form-check-label">First radio</label>
</div>

<!-- Inline Checkboxes -->
<div class="aiab-form-check aiab-form-check-inline">
  <input type="checkbox" id="inline-check1" class="aiab-form-check-input">
  <label for="inline-check1" class="aiab-form-check-label">Inline 1</label>
</div>

Form Sizes

Different Input Sizes
<!-- Large Input -->
<input type="text" class="aiab-form-control aiab-form-control-lg" placeholder="Large input">

<!-- Default Input -->
<input type="text" class="aiab-form-control" placeholder="Default input">

<!-- Small Input -->
<input type="text" class="aiab-form-control aiab-form-control-sm" placeholder="Small input">

Floating Labels

Floating Label Inputs
<div class="aiab-form-floating">
  <input type="text" id="floating-text" class="aiab-form-control" placeholder="Name">
  <label for="floating-text">Full Name</label>
</div>

<div class="aiab-form-floating">
  <input type="email" id="floating-email" class="aiab-form-control" placeholder="name@example.com">
  <label for="floating-email">Email address</label>
</div>

<div class="aiab-form-floating">
  <select id="floating-select" class="aiab-form-control">
    <option selected>Open this select menu</option>
    <option value="1">One</option>
    <option value="2">Two</option>
  </select>
  <label for="floating-select">Works with selects</label>
</div>

Form Validation

Validation States
Great! This field is valid.
Please provide a valid input.
This is some helpful text to guide the user.
You must agree before submitting.
<!-- Valid Input -->
<div class="aiab-form-group">
  <label for="valid-input">Valid Input</label>
  <input type="text" id="valid-input" class="aiab-form-control aiab-is-valid" value="This looks good!">
  <div class="valid-feedback">Great! This field is valid.</div>
</div>

<!-- Invalid Input -->
<div class="aiab-form-group">
  <label for="invalid-input">Invalid Input</label>
  <input type="text" id="invalid-input" class="aiab-form-control aiab-is-invalid">
  <div class="invalid-feedback">Please provide a valid input.</div>
</div>

<!-- Help Text -->
<div class="aiab-form-group">
  <label for="help-input">Input with Help Text</label>
  <input type="text" id="help-input" class="aiab-form-control">
  <div class="aiab-form-text">This is some helpful text.</div>
</div>

Form Layouts

Grid Layout

Form Grid System
<!-- Two Column Grid -->
<div class="aiab-form-grid-2">
  <div class="aiab-form-group">
    <label for="first-name">First Name</label>
    <input type="text" id="first-name" class="aiab-form-control">
  </div>
  <div class="aiab-form-group">
    <label for="last-name">Last Name</label>
    <input type="text" id="last-name" class="aiab-form-control">
  </div>
</div>

<!-- Three Column Grid -->
<div class="aiab-form-grid-3">
  <div class="aiab-form-group">
    <label for="city">City</label>
    <input type="text" id="city" class="aiab-form-control">
  </div>
  <div class="aiab-form-group">
    <label for="state">State</label>
    <select id="state" class="aiab-form-control">...</select>
  </div>
  <div class="aiab-form-group">
    <label for="zip">Zip</label>
    <input type="text" id="zip" class="aiab-form-control">
  </div>
</div>

Inline Form

Inline Form Example
<form class="aiab-form-inline">
  <div class="aiab-form-group">
    <label for="inline-name">Name</label>
    <input type="text" id="inline-name" class="aiab-form-control" placeholder="Jane Doe">
  </div>
  <div class="aiab-form-group">
    <label for="inline-email">Email</label>
    <input type="email" id="inline-email" class="aiab-form-control" placeholder="jane@example.com">
  </div>
  <button type="submit" class="aiab-btn aiab-btn--primary">Sign up</button>
</form>

Special Input Types

Range, File, and Search Inputs
Current value: 50
<!-- Range Input -->
<div class="aiab-form-group">
  <label for="range-input">Range Input</label>
  <input type="range" id="range-input" class="aiab-form-control" min="0" max="100" value="50">
</div>

<!-- File Input -->
<div class="aiab-form-group">
  <label for="file-input">File Input</label>
  <input type="file" id="file-input" class="aiab-form-control">
</div>

<!-- Search Form -->
<div class="aiab-search-form">
  <input type="search" class="aiab-form-control" placeholder="Search...">
  <button type="submit">🔍</button>
</div>

Complete Form Example

Contact Form with Validation
Contact Information
Please enter your first name.
Please enter your last name.
Please enter a valid email address.
Please select a subject.
Please enter your message.
You must agree to the terms and conditions.
<form id="contact-form" novalidate>
  <fieldset>
    <legend>Contact Information</legend>

    <div class="aiab-form-grid-2">
      <div class="aiab-form-group">
        <label for="first-name">First Name *</label>
        <input type="text" id="first-name" class="aiab-form-control" required>
        <div class="invalid-feedback">Please enter your first name.</div>
      </div>
      <div class="aiab-form-group">
        <label for="last-name">Last Name *</label>
        <input type="text" id="last-name" class="aiab-form-control" required>
        <div class="invalid-feedback">Please enter your last name.</div>
      </div>
    </div>

    <div class="aiab-form-group">
      <label for="email">Email Address *</label>
      <input type="email" id="email" class="aiab-form-control" required>
      <div class="invalid-feedback">Please enter a valid email address.</div>
    </div>

    <div class="aiab-form-group">
      <button type="submit" class="aiab-btn aiab-btn--primary">Send Message</button>
    </div>
  </fieldset>
</form>

CSS Classes Reference

Form Control Classes

Class Description
.aiab-form-control Base form control styling
.aiab-form-control-sm Small form control
.aiab-form-control-lg Large form control
.aiab-form-group Form field grouping aiab-container
.aiab-form-text / .aiab-help-text Helper text for form fields

Layout Classes

Class Description
.aiab-form-inline Inline form layout
.aiab-form-grid Auto-fit aiab-grid layout
.aiab-form-grid-2 Two-column aiab-grid layout
.aiab-form-grid-3 Three-column aiab-grid layout
.aiab-form-row Flex aiab-row for form fields

Checkbox/Radio Classes

Class Description
.aiab-form-check Checkbox/radio wrapper
.aiab-form-check-input Checkbox/radio input
.aiab-form-check-label Checkbox/radio label
.aiab-form-check-inline Inline checkbox/radio

Floating Label Classes

Class Description
.aiab-form-floating Floating label aiab-container

Validation Classes

Class Description
.aiab-is-valid Valid form control state
.aiab-is-invalid Invalid form control state
.valid-feedback Valid state feedback message
.invalid-feedback Invalid state feedback message
.was-validated Form validation trigger class

Special Input Classes

Class Description
.aiab-search-form Search input with button

JavaScript Integration

// Form validation utility
class FormValidator {
  constructor(form) {
    this.form = form;
    this.init();
  }

  init() {
    this.form.addEventListener('submit', (e) => this.handleSubmit(e));
    this.form.addEventListener('input', (e) => this.handleInput(e));
    this.form.addEventListener('change', (e) => this.handleChange(e));
  }

  handleSubmit(e) {
    e.preventDefault();

    if (this.validateForm()) {
      this.onValidSubmit();
    } else {
      this.onInvalidSubmit();
    }
  }

  handleInput(e) {
    const field = e.target;
    if (field.classList.contains('aiab-is-invalid') || field.classList.contains('aiab-is-valid')) {
      this.validateField(field);
    }
  }

  handleChange(e) {
    this.validateField(e.target);
  }

  validateForm() {
    const fields = this.form.querySelectorAll('input, select, textarea');
    let isValid = true;

    fields.forEach(field => {
      if (!this.validateField(field)) {
        isValid = false;
      }
    });

    this.form.classList.add('was-validated');
    return isValid;
  }

  validateField(field) {
    const isRequired = field.hasAttribute('required');
    const isEmpty = !field.value.trim();
    const isValidType = this.validateFieldType(field);

    let isValid = true;

    if (isRequired && isEmpty) {
      isValid = false;
    } else if (!isEmpty && !isValidType) {
      isValid = false;
    }

    this.updateFieldState(field, isValid);
    return isValid;
  }

  validateFieldType(field) {
    const type = field.type;
    const value = field.value.trim();

    if (!value) return true; // Empty values are handled by required check

    aiab-switch (type) {
      case 'email':
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
      case 'url':
        try {
          new URL(value);
          return true;
        } catch {
          return false;
        }
      case 'tel':
        return /^[\+]?[1-9][\d]{0,15}$/.test(value.replace(/[-\s\(\)]/g, ''));
      default:
        return field.checkValidity();
    }
  }

  updateFieldState(field, isValid) {
    field.classList.remove('aiab-is-valid', 'aiab-is-invalid');
    field.classList.add(isValid ? 'aiab-is-valid' : 'aiab-is-invalid');

    // Update feedback messages
    const feedback = field.parentNode.querySelector(
      isValid ? '.valid-feedback' : '.invalid-feedback'
    );
    if (feedback) {
      feedback.style.display = 'block';
    }

    // Hide opposite feedback
    const oppositeFeedback = field.parentNode.querySelector(
      isValid ? '.invalid-feedback' : '.valid-feedback'
    );
    if (oppositeFeedback) {
      oppositeFeedback.style.display = 'none';
    }
  }

  onValidSubmit() {
    // Handle successful form submission
    console.log('Form is valid and ready to submit');

    // Show success message
    this.showMessage('Form submitted successfully!', 'success');

    // You can add AJAX submission here
    // this.submitFormData();
  }

  onInvalidSubmit() {
    // Handle invalid form submission
    console.log('Form has validation errors');

    // Focus first invalid field
    const firstInvalid = this.form.querySelector('.aiab-is-invalid');
    if (firstInvalid) {
      firstInvalid.focus();
    }

    this.showMessage('Please fix the errors below.', 'error');
  }

  showMessage(text, type) {
    // Create and show aiab-alert message
    const alert = document.createElement('div');
    alert.className = `aiab-alert aiab-alert--${type}`;
    alert.textContent = text;

    this.form.insertBefore(alert, this.form.firstChild);

    // Remove after 5 seconds
    setTimeout(() => alert.remove(), 5000);
  }

  reset() {
    this.form.reset();
    this.form.classList.remove('was-validated');

    // Clear all validation states
    const fields = this.form.querySelectorAll('.aiab-is-valid, .aiab-is-invalid');
    fields.forEach(field => {
      field.classList.remove('aiab-is-valid', 'aiab-is-invalid');
    });
  }
}

// Auto-initialize forms with validation
document.addEventListener('DOMContentLoaded', () => {
  const forms = document.querySelectorAll('form[data-validate]');
  forms.forEach(form => new FormValidator(form));
});

// Range input value display
function updateRangeValue(input, displayElement) {
  displayElement.textContent = input.value;
}

// Search form enhancement
function enhanceSearchForms() {
  const searchForms = document.querySelectorAll('.aiab-search-form');

  searchForms.forEach(form => {
    const input = form.querySelector('input[type="search"]');
    const button = form.querySelector('button');

    if (input && button) {
      // Submit on button click
      button.addEventListener('click', (e) => {
        e.preventDefault();
        performSearch(input.value);
      });

      // Submit on Enter key
      input.addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
          e.preventDefault();
          performSearch(input.value);
        }
      });
    }
  });
}

function performSearch(query) {
  console.log('Searching for:', query);
  // Implement your search logic here
}

// Initialize enhancements
document.addEventListener('DOMContentLoaded', () => {
  enhanceSearchForms();

  // Initialize range value displays
  const rangeInputs = document.querySelectorAll('input[type="range"]');
  rangeInputs.forEach(input => {
    const display = document.getElementById('range-value');
    if (display) {
      input.addEventListener('input', () => updateRangeValue(input, display));
    }
  });
});

Best Practices

Form Structure

User Experience

Accessibility

Performance