Skip to main content
updated code based on comments
Source Link
tony
  • 403
  • 2
  • 10

Added:

  • Form validation using pattern attribute, thanks morbusg
  • Allowed for pasting ISO yyyy-mm-dd formats, along with mm/dd/yyyy and m/d/yyyy, thanks J-H
const dateInputdateInputs = document.getElementByIdquerySelectorAll('dateInput''.date-input');

dateInputs.forEach(dateInput => {
    let lastValue = ""; // To keep track of the previous value for backspace detection
    
    dateInput.addEventListener('input', function() {
        let val = dateInputthis.value;

        // If backspacing, skip the rest of the formatting
        if (lastValue && lastValue.length > val.length) {
            lastValue = val;
            return;
        }

        if (val.endsWith('/')) {
            val = val.slice(0, -1); // Remove the manually entered slash
            if (val.length === 1) {
                val = '0' + val + '/';
            } else if (val.length === 4) {
                val = val.slice(0, 3) + '0' + val.slice(3) + '/';
            }
        }

        val = val.replace(/\D/g, ''); // Remove any non-digit characters

        // Apply the MM/DD/YYYY format with constraints
        if (val.length === 1 && parseInt(val, 10) > 1) {
            val = '0' + val + '/';
        } else if (val.length >= 2) {
            let month = parseInt(val.substring(0, 2), 10);
            if (month === 0) month = 1;
            if (month > 12) month = 12;
            val = (month < 10 ? '0' + month : month) + '/' + val.substring(2);
        }

        if (val.length === 4 && parseInt(val.substring(3, 4), 10) > 3) {
            val = val.substring(0, 3) + '0' + val.substring(3) + '/';
        } else if (val.length >= 5) {
            let day = parseInt(val.substring(3, 5), 10);
            if (day === 0) day = 1;
            if (day > 31) day = 31;
            val = val.substring(0, 3) + (day < 10 ? '0' + day : day) + '/' + val.substring(5);
        }

        if (val.length === 7) {
            const yearStart = parseInt(val.substring(6, 7), 10);
            if (yearStart >= 4 && yearStart <= 9) { // If between 4 - 9 assume 1900's
                val = val.substring(0, 6) + '19' + val.substring(6);
            } else if (yearStart === 0 || yearStart === 3) { // If between 0 or 3 assume 2000's
                val = val.substring(0, 6) + '20' + val.substring(6);
            }
        } else if (val.length >= 10) {
            let year = parseInt(val.substring(6, 10), 10);
            if (year < 1900) {
                year = 1900;
            } else if (year > 2100) {
                year = 2100;
            }
            val = val.substring(0, 6) + year;
        }

        dateInputthis.value = val;
        lastValue = val;

        dateInput.addEventListener('paste', function(e) {
            e.preventDefault();
            const clipboardData = e.clipboardData || window.clipboardData;
            let pastedData = clipboardData.getData('Text');

            if (isISOFormat(pastedData)) {
                this.value = convertFromISOFormat(pastedData);
            } 
            else if (isShortDateFormat(pastedData)) {
                this.value = convertFromShortFormat(pastedData);
            } 
            else if (isStandardDateFormat(pastedData)) {
                this.value = pastedData;
            } 
            else {
                // If it doesn't match any of the allowed formats, don't set the value.
                this.value = "";
                alert("Please paste a date in the correct format!");
                return;
            }

            let event = new Event('input', {
                'bubbles': true,
                'cancelable': true
            });
            dateInput.dispatchEvent(event); // manually dispatch input event to trigger your input handler after paste
        });

    });

    // Prevent users from entering non-digit characters, except slash
    dateInput.addEventListener('keydown', function(e) {
        if (!isNumericEventisAllowedDateKeyEvent(e)) {
            e.preventDefault();
        }
    });
});

// Check if it's in yyyy-mm-dd format
function isNumericEventisISOFormat(edate) {
    const isoPattern = /^\d{4}-\d{2}-\d{2}$/;
 let charCode = ereturn isoPattern.keyCode;test(date);
}

// Convert yyyy-mm-dd to MM/DD/YYYY
function convertFromISOFormat(isoDate) {
    ifconst parts = isoDate.split(charCode'-');
 > 31 && return `${parts[1]}/${parts[2]}/${parts[0]}`;
}

// Check if it's in m/d/yyyy format
function isShortDateFormat(charCodedate) <{
 48 || charCode >const 57shortDatePattern = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
    return shortDatePattern.test(date);
}

// &&Convert charCodem/d/yyyy !==to 37MM/DD/YYYY
function &&convertFromShortFormat(shortDate) charCode{
 !== 39 && charCodeconst !==parts 8= &&shortDate.split('/');
 charCode !== 46 &&const charCodemonth !=== 191parts[0].padStart(2, '0');
    const day = parts[1].padStart(2, '0');
    const year = parts[2];
    return `${month}/${day}/${year}`;
}

// Check if it's in mm/dd/yyyy format
function isStandardDateFormat(date) {
    const standardDatePattern = /^\d{2}\/\d{2}\/\d{4}$/;
    return false;standardDatePattern.test(date);
}

function isAllowedDateKeyEvent(e) {
    let charCode }= e.keyCode;

    // Allow CTRL key or CMD key on Mac (e.metaKey)
    if (e.ctrlKey || e.metaKey) {
        return true;
    }

    if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 37 && charCode !== 39 && charCode !== 8 && charCode !== 46 && charCode !== 191) {
        return false;
    }

    return true;
}
<input type="text" id="dateInput"class="date-input" placeholder="mm/dd/yyyy" pattern="\d*">pattern="\d{2}/\d{2}/\d{4}" inputmode="numeric">
const dateInput = document.getElementById('dateInput');

    let lastValue = ""; // To keep track of the previous value for backspace detection
    
    dateInput.addEventListener('input', function() {
        let val = dateInput.value;

        // If backspacing, skip the rest of the formatting
        if (lastValue && lastValue.length > val.length) {
            lastValue = val;
            return;
        }

        if (val.endsWith('/')) {
            val = val.slice(0, -1); // Remove the manually entered slash
            if (val.length === 1) {
                val = '0' + val + '/';
            } else if (val.length === 4) {
                val = val.slice(0, 3) + '0' + val.slice(3) + '/';
            }
        }

        val = val.replace(/\D/g, ''); // Remove any non-digit characters

        // Apply the MM/DD/YYYY format with constraints
        if (val.length === 1 && parseInt(val, 10) > 1) {
            val = '0' + val + '/';
        } else if (val.length >= 2) {
            let month = parseInt(val.substring(0, 2), 10);
            if (month === 0) month = 1;
            if (month > 12) month = 12;
            val = (month < 10 ? '0' + month : month) + '/' + val.substring(2);
        }

        if (val.length === 4 && parseInt(val.substring(3, 4), 10) > 3) {
            val = val.substring(0, 3) + '0' + val.substring(3) + '/';
        } else if (val.length >= 5) {
            let day = parseInt(val.substring(3, 5), 10);
            if (day === 0) day = 1;
            if (day > 31) day = 31;
            val = val.substring(0, 3) + (day < 10 ? '0' + day : day) + '/' + val.substring(5);
        }

        if (val.length === 7) {
          const yearStart = parseInt(val.substring(6, 7), 10);
          if (yearStart >= 4 && yearStart <= 9) { // If between 4 - 9 assume 1900's
            val = val.substring(0, 6) + '19' + val.substring(6);
          } else if (yearStart === 0 || yearStart === 3) { // If between 0 or 3 assume 2000's
            val = val.substring(0, 6) + '20' + val.substring(6);
          }
        } else if (val.length >= 10) {
          let year = parseInt(val.substring(6, 10), 10);
          if (year < 1900) {
            year = 1900;
          } else if (year > 2100) {
            year = 2100;
          }
          val = val.substring(0, 6) + year;
        }

        dateInput.value = val;
        lastValue = val;
    });

    // Prevent users from entering non-digit characters, except slash
    dateInput.addEventListener('keydown', function(e) {
        if (!isNumericEvent(e)) {
            e.preventDefault();
        }
    });

    function isNumericEvent(e) {
        let charCode = e.keyCode;
        if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 37 && charCode !== 39 && charCode !== 8 && charCode !== 46 && charCode !== 191) {
            return false;
        }
        return true;
    }
<input type="text" id="dateInput" placeholder="mm/dd/yyyy" pattern="\d*">

Added:

  • Form validation using pattern attribute, thanks morbusg
  • Allowed for pasting ISO yyyy-mm-dd formats, along with mm/dd/yyyy and m/d/yyyy, thanks J-H
const dateInputs = document.querySelectorAll('.date-input');

dateInputs.forEach(dateInput => {
    let lastValue = ""; // To keep track of the previous value for backspace detection

    dateInput.addEventListener('input', function() {
        let val = this.value;

        // If backspacing, skip the rest of the formatting
        if (lastValue && lastValue.length > val.length) {
            lastValue = val;
            return;
        }

        if (val.endsWith('/')) {
            val = val.slice(0, -1); // Remove the manually entered slash
            if (val.length === 1) {
                val = '0' + val + '/';
            } else if (val.length === 4) {
                val = val.slice(0, 3) + '0' + val.slice(3) + '/';
            }
        }

        val = val.replace(/\D/g, ''); // Remove any non-digit characters

        // Apply the MM/DD/YYYY format with constraints
        if (val.length === 1 && parseInt(val, 10) > 1) {
            val = '0' + val + '/';
        } else if (val.length >= 2) {
            let month = parseInt(val.substring(0, 2), 10);
            if (month === 0) month = 1;
            if (month > 12) month = 12;
            val = (month < 10 ? '0' + month : month) + '/' + val.substring(2);
        }

        if (val.length === 4 && parseInt(val.substring(3, 4), 10) > 3) {
            val = val.substring(0, 3) + '0' + val.substring(3) + '/';
        } else if (val.length >= 5) {
            let day = parseInt(val.substring(3, 5), 10);
            if (day === 0) day = 1;
            if (day > 31) day = 31;
            val = val.substring(0, 3) + (day < 10 ? '0' + day : day) + '/' + val.substring(5);
        }

        if (val.length === 7) {
            const yearStart = parseInt(val.substring(6, 7), 10);
            if (yearStart >= 4 && yearStart <= 9) { // If between 4 - 9 assume 1900's
                val = val.substring(0, 6) + '19' + val.substring(6);
            } else if (yearStart === 0 || yearStart === 3) { // If between 0 or 3 assume 2000's
                val = val.substring(0, 6) + '20' + val.substring(6);
            }
        } else if (val.length >= 10) {
            let year = parseInt(val.substring(6, 10), 10);
            if (year < 1900) {
                year = 1900;
            } else if (year > 2100) {
                year = 2100;
            }
            val = val.substring(0, 6) + year;
        }

        this.value = val;
        lastValue = val;

        dateInput.addEventListener('paste', function(e) {
            e.preventDefault();
            const clipboardData = e.clipboardData || window.clipboardData;
            let pastedData = clipboardData.getData('Text');

            if (isISOFormat(pastedData)) {
                this.value = convertFromISOFormat(pastedData);
            } 
            else if (isShortDateFormat(pastedData)) {
                this.value = convertFromShortFormat(pastedData);
            } 
            else if (isStandardDateFormat(pastedData)) {
                this.value = pastedData;
            } 
            else {
                // If it doesn't match any of the allowed formats, don't set the value.
                this.value = "";
                alert("Please paste a date in the correct format!");
                return;
            }

            let event = new Event('input', {
                'bubbles': true,
                'cancelable': true
            });
            dateInput.dispatchEvent(event); // manually dispatch input event to trigger your input handler after paste
        });

    });

    // Prevent users from entering non-digit characters, except slash
    dateInput.addEventListener('keydown', function(e) {
        if (!isAllowedDateKeyEvent(e)) {
            e.preventDefault();
        }
    });
});

// Check if it's in yyyy-mm-dd format
function isISOFormat(date) {
    const isoPattern = /^\d{4}-\d{2}-\d{2}$/;
    return isoPattern.test(date);
}

// Convert yyyy-mm-dd to MM/DD/YYYY
function convertFromISOFormat(isoDate) {
    const parts = isoDate.split('-');
    return `${parts[1]}/${parts[2]}/${parts[0]}`;
}

// Check if it's in m/d/yyyy format
function isShortDateFormat(date) {
    const shortDatePattern = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
    return shortDatePattern.test(date);
}

// Convert m/d/yyyy to MM/DD/YYYY
function convertFromShortFormat(shortDate) {
    const parts = shortDate.split('/');
    const month = parts[0].padStart(2, '0');
    const day = parts[1].padStart(2, '0');
    const year = parts[2];
    return `${month}/${day}/${year}`;
}

// Check if it's in mm/dd/yyyy format
function isStandardDateFormat(date) {
    const standardDatePattern = /^\d{2}\/\d{2}\/\d{4}$/;
    return standardDatePattern.test(date);
}

function isAllowedDateKeyEvent(e) {
    let charCode = e.keyCode;

    // Allow CTRL key or CMD key on Mac (e.metaKey)
    if (e.ctrlKey || e.metaKey) {
        return true;
    }

    if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 37 && charCode !== 39 && charCode !== 8 && charCode !== 46 && charCode !== 191) {
        return false;
    }

    return true;
}
<input type="text" class="date-input" placeholder="mm/dd/yyyy" pattern="\d{2}/\d{2}/\d{4}" inputmode="numeric">
Added year logic
Source Link
tony
  • 403
  • 2
  • 10
  • Enforce a month value range from 01 to 12.
  • Ensure day values stay within the 01 to 31 range.
  • Set the year value boundaries between 1900 and 20502100.
  • If two digits year starting with 0 or 3 is entered year is assumed 1900s.
  • If two digits year starting with 4 - 9 is entered year is assumed to be 2000s.
  • Automatically advance from the month to day section when the first digit of the month exceeds 1.
  • Move the cursor to the year section when the initial digit of the day goes beyond 3.
  • Recognize a manually entered slash (/), and, if needed, precede it with a leading zero before transitioning to the next segment.
  • Filter out non-numeric inputs, with the sole exception being a manually entered slash (/).
  • Adjust a 00 entry for month or day to 01 for better consistency.
  • Permit the backspace functionality to clear fields without default autofill interruptions.
const dateInput = document.getElementById('dateInput');

    let lastValue = ""; // To keep track of the previous value for backspace detection
    
    dateInput.addEventListener('input', function() {
        let val = dateInput.value;

        // If backspacing, skip the rest of the formatting
        if (lastValue && lastValue.length > val.length) {
            lastValue = val;
            return;
        }

        if (val.endsWith('/')) {
            val = val.slice(0, -1); // Remove the manually entered slash
            if (val.length === 1) {
                val = '0' + val + '/';
            } else if (val.length === 4) {
                val = val.slice(0, 3) + '0' + val.slice(3) + '/';
            }
        }

        val = val.replace(/\D/g, ''); // Remove any non-digit characters

        // Apply the MM/DD/YYYY format with constraints
        if (val.length === 1 && parseInt(val, 10) > 1) {
            val = '0' + val + '/';
        } else if (val.length >= 2) {
            let month = parseInt(val.substring(0, 2), 10);
            if (month === 0) month = 1;
            if (month > 12) month = 12;
            val = (month < 10 ? '0' + month : month) + '/' + val.substring(2);
        }

        if (val.length === 4 && parseInt(val.substring(3, 4), 10) > 3) {
            val = val.substring(0, 3) + '0' + val.substring(3) + '/';
        } else if (val.length >= 5) {
            let day = parseInt(val.substring(3, 5), 10);
            if (day === 0) day = 1;
            if (day > 31) day = 31;
            val = val.substring(0, 3) + (day < 10 ? '0' + day : day) + '/' + val.substring(5);
        }

        if (val.length >==== 107) {
            letconst yearyearStart = parseInt(val.substring(6, 107), 10);
          if (yearStart >= 4 && yearStart <= 9) { // If between 4 - 9 assume 1900's
            val = val.substring(0, 6) + '19' + val.substring(6);
          } else if (yearyearStart <=== 19000 || yearStart === 3) {
  // If between 0 or 3 assume 2000's
            yearval = 1900;val.substring(0, 6) + '20' + val.substring(6);
          }
        } else if (yearval.length >>= 205010) {
          let year = parseInt(val.substring(6, 10), 10);
          if (year < 1900) {
            year = 2050;1900;
          } else }if (year > 2100) {
            year = 2100;
          }
          val = val.substring(0, 6) + year;
        }

        dateInput.value = val;
        lastValue = val;
    });

    // Prevent users from entering non-digit characters, except slash
    dateInput.addEventListener('keydown', function(e) {
        if (!isNumericEvent(e)) {
            e.preventDefault();
        }
    });

    function isNumericEvent(e) {
        let charCode = e.keyCode;
        if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 37 && charCode !== 39 && charCode !== 8 && charCode !== 46 && charCode !== 191) {
            return false;
        }
        return true;
    }
<input type="text" id="dateInput" placeholder="mm/dd/yyyy" pattern="\d*">
  • Enforce a month value range from 01 to 12.
  • Ensure day values stay within the 01 to 31 range.
  • Set the year value boundaries between 1900 and 2050.
  • Automatically advance from the month to day section when the first digit of the month exceeds 1.
  • Move the cursor to the year section when the initial digit of the day goes beyond 3.
  • Recognize a manually entered slash (/), and, if needed, precede it with a leading zero before transitioning to the next segment.
  • Filter out non-numeric inputs, with the sole exception being a manually entered slash (/).
  • Adjust a 00 entry for month or day to 01 for better consistency.
  • Permit the backspace functionality to clear fields without default autofill interruptions.
const dateInput = document.getElementById('dateInput');

    let lastValue = ""; // To keep track of the previous value for backspace detection
    
    dateInput.addEventListener('input', function() {
        let val = dateInput.value;

        // If backspacing, skip the rest of the formatting
        if (lastValue && lastValue.length > val.length) {
            lastValue = val;
            return;
        }

        if (val.endsWith('/')) {
            val = val.slice(0, -1); // Remove the manually entered slash
            if (val.length === 1) {
                val = '0' + val + '/';
            } else if (val.length === 4) {
                val = val.slice(0, 3) + '0' + val.slice(3) + '/';
            }
        }

        val = val.replace(/\D/g, ''); // Remove any non-digit characters

        // Apply the MM/DD/YYYY format with constraints
        if (val.length === 1 && parseInt(val, 10) > 1) {
            val = '0' + val + '/';
        } else if (val.length >= 2) {
            let month = parseInt(val.substring(0, 2), 10);
            if (month === 0) month = 1;
            if (month > 12) month = 12;
            val = (month < 10 ? '0' + month : month) + '/' + val.substring(2);
        }

        if (val.length === 4 && parseInt(val.substring(3, 4), 10) > 3) {
            val = val.substring(0, 3) + '0' + val.substring(3) + '/';
        } else if (val.length >= 5) {
            let day = parseInt(val.substring(3, 5), 10);
            if (day === 0) day = 1;
            if (day > 31) day = 31;
            val = val.substring(0, 3) + (day < 10 ? '0' + day : day) + '/' + val.substring(5);
        }

        if (val.length >= 10) {
            let year = parseInt(val.substring(6, 10), 10);
            if (year < 1900) {
                 year = 1900;
            } else if (year > 2050) {
                year = 2050;
            }

            val = val.substring(0, 6) + year;
        }

        dateInput.value = val;
        lastValue = val;
    });

    // Prevent users from entering non-digit characters, except slash
    dateInput.addEventListener('keydown', function(e) {
        if (!isNumericEvent(e)) {
            e.preventDefault();
        }
    });

    function isNumericEvent(e) {
        let charCode = e.keyCode;
        if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 37 && charCode !== 39 && charCode !== 8 && charCode !== 46 && charCode !== 191) {
            return false;
        }
        return true;
    }
<input type="text" id="dateInput" placeholder="mm/dd/yyyy" pattern="\d*">
  • Enforce a month value range from 01 to 12.
  • Ensure day values stay within the 01 to 31 range.
  • Set the year value boundaries between 1900 and 2100.
  • If two digits year starting with 0 or 3 is entered year is assumed 1900s.
  • If two digits year starting with 4 - 9 is entered year is assumed to be 2000s.
  • Automatically advance from the month to day section when the first digit of the month exceeds 1.
  • Move the cursor to the year section when the initial digit of the day goes beyond 3.
  • Recognize a manually entered slash (/), and, if needed, precede it with a leading zero before transitioning to the next segment.
  • Filter out non-numeric inputs, with the sole exception being a manually entered slash (/).
  • Adjust a 00 entry for month or day to 01 for better consistency.
  • Permit the backspace functionality to clear fields without default autofill interruptions.
const dateInput = document.getElementById('dateInput');

    let lastValue = ""; // To keep track of the previous value for backspace detection
    
    dateInput.addEventListener('input', function() {
        let val = dateInput.value;

        // If backspacing, skip the rest of the formatting
        if (lastValue && lastValue.length > val.length) {
            lastValue = val;
            return;
        }

        if (val.endsWith('/')) {
            val = val.slice(0, -1); // Remove the manually entered slash
            if (val.length === 1) {
                val = '0' + val + '/';
            } else if (val.length === 4) {
                val = val.slice(0, 3) + '0' + val.slice(3) + '/';
            }
        }

        val = val.replace(/\D/g, ''); // Remove any non-digit characters

        // Apply the MM/DD/YYYY format with constraints
        if (val.length === 1 && parseInt(val, 10) > 1) {
            val = '0' + val + '/';
        } else if (val.length >= 2) {
            let month = parseInt(val.substring(0, 2), 10);
            if (month === 0) month = 1;
            if (month > 12) month = 12;
            val = (month < 10 ? '0' + month : month) + '/' + val.substring(2);
        }

        if (val.length === 4 && parseInt(val.substring(3, 4), 10) > 3) {
            val = val.substring(0, 3) + '0' + val.substring(3) + '/';
        } else if (val.length >= 5) {
            let day = parseInt(val.substring(3, 5), 10);
            if (day === 0) day = 1;
            if (day > 31) day = 31;
            val = val.substring(0, 3) + (day < 10 ? '0' + day : day) + '/' + val.substring(5);
        }

        if (val.length === 7) {
          const yearStart = parseInt(val.substring(6, 7), 10);
          if (yearStart >= 4 && yearStart <= 9) { // If between 4 - 9 assume 1900's
            val = val.substring(0, 6) + '19' + val.substring(6);
          } else if (yearStart === 0 || yearStart === 3) { // If between 0 or 3 assume 2000's
            val = val.substring(0, 6) + '20' + val.substring(6);
          }
        } else if (val.length >= 10) {
          let year = parseInt(val.substring(6, 10), 10);
          if (year < 1900) {
            year = 1900;
          } else if (year > 2100) {
            year = 2100;
          }
          val = val.substring(0, 6) + year;
        }

        dateInput.value = val;
        lastValue = val;
    });

    // Prevent users from entering non-digit characters, except slash
    dateInput.addEventListener('keydown', function(e) {
        if (!isNumericEvent(e)) {
            e.preventDefault();
        }
    });

    function isNumericEvent(e) {
        let charCode = e.keyCode;
        if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 37 && charCode !== 39 && charCode !== 8 && charCode !== 46 && charCode !== 191) {
            return false;
        }
        return true;
    }
<input type="text" id="dateInput" placeholder="mm/dd/yyyy" pattern="\d*">
Source Link
tony
  • 403
  • 2
  • 10

Smart and Inututive Auto-Format Date Input

I'm developing a custom date input format to enhance user experience in scenarios where birthdays and expiration dates are inputted. Traditional date fields and date picker libraries often fall short in offering intuitive user interactions. My script has been designed to:

  • Enforce a month value range from 01 to 12.
  • Ensure day values stay within the 01 to 31 range.
  • Set the year value boundaries between 1900 and 2050.
  • Automatically advance from the month to day section when the first digit of the month exceeds 1.
  • Move the cursor to the year section when the initial digit of the day goes beyond 3.
  • Recognize a manually entered slash (/), and, if needed, precede it with a leading zero before transitioning to the next segment.
  • Filter out non-numeric inputs, with the sole exception being a manually entered slash (/).
  • Adjust a 00 entry for month or day to 01 for better consistency.
  • Permit the backspace functionality to clear fields without default autofill interruptions.

My goal is to optimize user interactions, ensuring the underlying code is robust, reliable, and widely compatible across browsers.

const dateInput = document.getElementById('dateInput');

    let lastValue = ""; // To keep track of the previous value for backspace detection
    
    dateInput.addEventListener('input', function() {
        let val = dateInput.value;

        // If backspacing, skip the rest of the formatting
        if (lastValue && lastValue.length > val.length) {
            lastValue = val;
            return;
        }

        if (val.endsWith('/')) {
            val = val.slice(0, -1); // Remove the manually entered slash
            if (val.length === 1) {
                val = '0' + val + '/';
            } else if (val.length === 4) {
                val = val.slice(0, 3) + '0' + val.slice(3) + '/';
            }
        }

        val = val.replace(/\D/g, ''); // Remove any non-digit characters

        // Apply the MM/DD/YYYY format with constraints
        if (val.length === 1 && parseInt(val, 10) > 1) {
            val = '0' + val + '/';
        } else if (val.length >= 2) {
            let month = parseInt(val.substring(0, 2), 10);
            if (month === 0) month = 1;
            if (month > 12) month = 12;
            val = (month < 10 ? '0' + month : month) + '/' + val.substring(2);
        }

        if (val.length === 4 && parseInt(val.substring(3, 4), 10) > 3) {
            val = val.substring(0, 3) + '0' + val.substring(3) + '/';
        } else if (val.length >= 5) {
            let day = parseInt(val.substring(3, 5), 10);
            if (day === 0) day = 1;
            if (day > 31) day = 31;
            val = val.substring(0, 3) + (day < 10 ? '0' + day : day) + '/' + val.substring(5);
        }

        if (val.length >= 10) {
            let year = parseInt(val.substring(6, 10), 10);
            if (year < 1900) {
                year = 1900;
            } else if (year > 2050) {
                year = 2050;
            }

            val = val.substring(0, 6) + year;
        }

        dateInput.value = val;
        lastValue = val;
    });

    // Prevent users from entering non-digit characters, except slash
    dateInput.addEventListener('keydown', function(e) {
        if (!isNumericEvent(e)) {
            e.preventDefault();
        }
    });

    function isNumericEvent(e) {
        let charCode = e.keyCode;
        if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 37 && charCode !== 39 && charCode !== 8 && charCode !== 46 && charCode !== 191) {
            return false;
        }
        return true;
    }
<input type="text" id="dateInput" placeholder="mm/dd/yyyy" pattern="\d*">