Native HTML5 validation works automatically with VanillaSmartSelect. The original select remains synchronized, allowing you to use standard attributes like required without any additional code.

Form with HTML5 Validation

Complete form example with required fields and native browser validation.

View code

HTML

<form id="customForm">
  <div>
    <label for="department">Department: *</label>
    <select id="department" required>
      <option value="">Select...</option>
      <option value="ti">TI</option>
      <option value="rh">RH</option>
      <option value="vendas">Vendas</option>
      <option value="marketing">Marketing</option>
    </select>
  </div>

  <div>
    <label for="level">Level: *</label>
    <select id="level" required>
      <option value="">Select...</option>
      <option value="junior">Junior</option>
      <option value="pleno">Mid-level</option>
      <option value="senior">Senior</option>
    </select>
  </div>

  <div>
    <label for="shift">Shift:</label>
    <select id="shift">
      <option value="">Select...</option>
      <option value="morning">Morning</option>
      <option value="afternoon">Afternoon</option>
      <option value="night">Night</option>
    </select>
  </div>

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

JavaScript

// Initialize selects
new VanillaSmartSelect('#department', { searchable: true });
new VanillaSmartSelect('#level', { searchable: true });
new VanillaSmartSelect('#shift', { searchable: true });

// Simple custom validation
const form = document.getElementById('customForm');
const resultDiv = document.getElementById('result');

form.addEventListener('submit', (e) => {
  e.preventDefault();

  if (form.checkValidity()) {
    // Valid - process
    const formData = new FormData(form);
    const data = Object.fromEntries(formData);

    resultDiv.className = 'result success';
    resultDiv.style.display = 'block';
    resultDiv.style.background = '#d4edda';
    resultDiv.style.border = '1px solid #28a745';
    resultDiv.style.color = '#155724';
    resultDiv.innerHTML = `
      <strong>✓ Valid Form!</strong><br>      
    `;

    console.log('Valid data:', data);
  } else {
    // Invalid - show error
    form.reportValidity(); // Native browser message

    resultDiv.style.display = 'block';
    resultDiv.style.background = '#f8d7da';
    resultDiv.style.border = '1px solid #dc3545';
    resultDiv.style.color = '#721c24';
    resultDiv.innerHTML = '<strong>✗ Error!</strong> Fill in all required fields.';
  }
});

Custom Validation with HTML5 API

Use the HTML5 validation API to define custom rules and error messages.

Only "High" or "Critical" are accepted
View code

HTML

<form id="customValidationForm">
  <div>
    <label for="custom-validation">Select a priority: *</label>
    <select id="custom-validation" required>
      <option value="">Select...</option>
      <option value="low">Low</option>
      <option value="medium">Medium</option>
      <option value="high">High</option>
      <option value="critical">Critical</option>
    </select>
  </div>

  <button type="submit">Submit</button>
  <button type="button" id="checkValidityBtn">Check Validity</button>
  <button type="button" id="showErrorBtn">Show Message</button>
</form>

JavaScript

const selectElement = document.querySelector('#custom-validation');
const select = new VanillaSmartSelect('#custom-validation');

// Validate when value changes
selectElement.addEventListener('change', () => {
  const value = selectElement.value;
  
  // Only "high" or "critical" are valid
  if (value && value !== 'high' && value !== 'critical') {
    selectElement.setCustomValidity('Only "High" or "Critical" priorities are allowed');
  } else {
    selectElement.setCustomValidity(''); // Clear error
  }
});

// Check validity programmatically
document.getElementById('checkValidityBtn').addEventListener('click', () => {
  if (selectElement.checkValidity()) {
    console.log('✓ Valid field!');
  } else {
    console.log('✗ Invalid field!');
  }
});

// Show validation message
document.getElementById('showErrorBtn').addEventListener('click', () => {
  selectElement.reportValidity(); // Shows native browser message
});

Field Dependency Validation

The "City" field can only be selected after choosing a "State".

View code

HTML

<form id="dependencyForm">
  <div>
    <label for="state">State: *</label>
    <select id="state" required>
      <option value="">Select a state...</option>
      <option value="sp">São Paulo</option>
      <option value="rj">Rio de Janeiro</option>
      <option value="mg">Minas Gerais</option>
      <option value="rs">Rio Grande do Sul</option>
    </select>
  </div>

  <div>
    <label for="city">City: *</label>
    <select id="city" required disabled>
      <option value="">Select a state first...</option>
    </select>
  </div>

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

JavaScript

// Initialize selects
new VanillaSmartSelect('#state');
new VanillaSmartSelect('#city');

// City data by state
const citiesByState = {
  sp: ['São Paulo', 'Campinas', 'Santos', 'Ribeirão Preto'],
  rj: ['Rio de Janeiro', 'Niterói', 'Petrópolis', 'Cabo Frio'],
  mg: ['Belo Horizonte', 'Uberlândia', 'Contagem', 'Juiz de Fora'],
  rs: ['Porto Alegre', 'Caxias do Sul', 'Pelotas', 'Canoas']
};

const stateSelect = document.querySelector('#state');
const citySelect = document.querySelector('#city');

stateSelect.addEventListener('change', () => {
  if (!stateSelect.value) {
    citySelect.disabled = true;
    citySelect.innerHTML = '<option value="">Select a state first...</option>';
    citySelect.setCustomValidity('Select a state first');
  } else {
    citySelect.disabled = false;
    citySelect.setCustomValidity('');
    
    // Fill cities from selected state
    const cities = citiesByState[stateSelect.value];
    citySelect.innerHTML = '<option value="">Select a city...</option>' +
      cities.map(city => `<option value="${city}">${city}</option>`).join('');
  }
});

Custom Validation with Regex

Validate if the product code follows a specific pattern (XXX-9999).

Valid format: 3 uppercase letters + hyphen + 4 numbers (ex: ABC-1234)
View code

HTML

<form id="regexForm">
  <div>
    <label for="product-code">Product Code: *</label>
    <select id="product-code" required>
      <option value="">Select a code...</option>
      <option value="ABC-1234">ABC-1234 ✓</option>
      <option value="XYZ-5678">XYZ-5678 ✓</option>
      <option value="DEF-9012">DEF-9012 ✓</option>
      <option value="INVALID">INVALID ✗</option>
      <option value="123-ABC">123-ABC ✗</option>
      <option value="AB-1234">AB-1234 ✗</option>
    </select>
  </div>

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

JavaScript

// Initialize select
new VanillaSmartSelect('#product-code');

const codeSelect = document.querySelector('#product-code');

// Validate when value changes
codeSelect.addEventListener('change', () => {
  const value = codeSelect.value;
  const pattern = /^[A-Z]{3}-\d{4}$/; // Ex: ABC-1234

  if (value && !pattern.test(value)) {
    codeSelect.setCustomValidity('Invalid code. Use the format: XXX-9999');
  } else {
    codeSelect.setCustomValidity('');
  }
});

How It Works

📋 Validation Principles:
  • Synchronized Original Select: VanillaSmartSelect keeps the original select always updated
  • required Attribute: Works natively without additional code
  • Automatic Red Border: Visual feedback when required field is empty
  • form.checkValidity(): Validates all fields at once
  • form.reportValidity(): Shows native browser error messages

Integration with Validation Libraries

Since the original select remains synchronized, you can use any validation library that works with the DOM:

Library Compatibility Note
HTML5 Validation ✅ Full Works natively, no configuration needed
Vuelidate ✅ Full Accesses the original select directly
Yup ✅ Full Schema-based validation works perfectly
Joi ✅ Full Reads FormData values automatically
Zod ✅ Full TypeScript-first, works with DOM
jQuery Validation ✅ Full Validates the original select, not the wrapper
✅ Why it works: VanillaSmartSelect is a visual wrapper that keeps the original HTML select in the DOM and always synchronized. Validation libraries can access and validate the original select normally.

Best Practices

📌 Recommendations:
  • Use HTML5 First: In most cases, native validation is sufficient
  • Visual Feedback: Required fields already show red border automatically
  • Clear Messages: Use setCustomValidity() for specific messages
  • Validate on Submit: Always validate on the form's submit event
  • Guaranteed Synchronization: The original select is always up to date
  • Scales Well: Same approach works for 10 or 100 fields
← Selection Limit Templates →