Advanced Markdown form validation and input handling systems enable interactive documentation with robust data validation, real-time user feedback, and comprehensive error handling mechanisms. By implementing sophisticated validation frameworks, dynamic input processing systems, and user-friendly feedback interfaces, technical teams can create documentation that not only informs but also collects, validates, and processes user input effectively while maintaining professional standards for data quality and user experience.

Why Master Form Validation and Input Handling?

Professional form validation provides essential benefits for interactive documentation:

  • Data Quality: Ensure user-submitted data meets requirements through comprehensive validation rules
  • User Experience: Provide immediate feedback and guidance to help users complete forms successfully
  • Security: Protect against malicious input and maintain data integrity through proper validation
  • Automation: Enable automated processing of validated user input for dynamic content generation
  • Accessibility: Create inclusive form experiences that work across different assistive technologies

Foundation Validation Principles

Comprehensive Input Validation Framework

Building robust validation systems that handle multiple input types and validation scenarios:

// form-validator.js - Advanced form validation system for Markdown documentation
class MarkdownFormValidator {
    constructor(options = {}) {
        this.options = {
            // Validation configuration
            validateOnInput: true,
            validateOnBlur: true,
            showErrorsInline: true,
            highlightInvalidFields: true,
            
            // Error display options
            errorClass: 'validation-error',
            successClass: 'validation-success',
            errorSummaryId: 'validation-summary',
            
            // Validation timing
            debounceDelay: 300,
            asyncValidationDelay: 500,
            
            // Custom validation rules
            customValidators: new Map(),
            
            // Internationalization
            locale: 'en',
            messages: {},
            
            ...options
        };
        
        this.validationRules = new Map();
        this.validationResults = new Map();
        this.validationQueue = new Map();
        this.validatedForms = new Set();
        
        this.setupDefaultValidators();
        this.init();
    }
    
    init() {
        this.loadValidationMessages();
        this.setupFormObserver();
        this.setupEventListeners();
        console.log('Markdown Form Validator initialized');
    }
    
    setupDefaultValidators() {
        // Basic validators
        this.addValidator('required', this.validateRequired.bind(this));
        this.addValidator('minLength', this.validateMinLength.bind(this));
        this.addValidator('maxLength', this.validateMaxLength.bind(this));
        this.addValidator('pattern', this.validatePattern.bind(this));
        this.addValidator('email', this.validateEmail.bind(this));
        this.addValidator('url', this.validateUrl.bind(this));
        this.addValidator('number', this.validateNumber.bind(this));
        
        // Advanced validators
        this.addValidator('custom', this.validateCustom.bind(this));
        this.addValidator('async', this.validateAsync.bind(this));
        this.addValidator('conditional', this.validateConditional.bind(this));
        this.addValidator('crossField', this.validateCrossField.bind(this));
        
        // Content-specific validators
        this.addValidator('markdown', this.validateMarkdown.bind(this));
        this.addValidator('codeBlock', this.validateCodeBlock.bind(this));
        this.addValidator('frontmatter', this.validateFrontmatter.bind(this));
    }
    
    addValidator(name, validatorFunction) {
        this.options.customValidators.set(name, validatorFunction);
    }
    
    loadValidationMessages() {
        const defaultMessages = {
            required: 'This field is required',
            minLength: 'Must be at least {min} characters long',
            maxLength: 'Must not exceed {max} characters',
            pattern: 'Please enter a valid value',
            email: 'Please enter a valid email address',
            url: 'Please enter a valid URL',
            number: 'Please enter a valid number',
            markdown: 'Invalid Markdown syntax',
            codeBlock: 'Code block contains syntax errors',
            frontmatter: 'Invalid YAML frontmatter',
            async: 'Validation failed',
            conditional: 'Field validation failed',
            crossField: 'Fields do not match'
        };
        
        this.options.messages = { ...defaultMessages, ...this.options.messages };
    }
    
    setupFormObserver() {
        // Observe DOM for new forms
        const observer = new MutationObserver((mutations) => {
            mutations.forEach((mutation) => {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        const forms = node.querySelectorAll ? 
                            node.querySelectorAll('form[data-validate]') : 
                            [];
                        
                        forms.forEach(form => this.initializeForm(form));
                        
                        // Check if the node itself is a form
                        if (node.matches && node.matches('form[data-validate]')) {
                            this.initializeForm(node);
                        }
                    }
                });
            });
        });
        
        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        
        // Initialize existing forms
        document.querySelectorAll('form[data-validate]').forEach(form => {
            this.initializeForm(form);
        });
    }
    
    initializeForm(form) {
        if (this.validatedForms.has(form)) return;
        
        this.validatedForms.add(form);
        const formId = form.id || `form-${Date.now()}`;
        form.id = formId;
        
        // Parse validation rules from data attributes
        this.parseFormValidationRules(form);
        
        // Setup form-level validation
        form.addEventListener('submit', (event) => {
            this.handleFormSubmit(event);
        });
        
        // Setup field-level validation
        const fields = form.querySelectorAll('[data-validate]');
        fields.forEach(field => {
            this.initializeField(field, form);
        });
        
        console.log(`Initialized form validation for ${formId}`);
    }
    
    initializeField(field, form) {
        const fieldName = field.name || field.id || `field-${Date.now()}`;
        
        // Parse field validation rules
        this.parseFieldValidationRules(field, form.id);
        
        // Setup event listeners
        if (this.options.validateOnInput) {
            const inputHandler = this.debounce(
                () => this.validateField(field, form),
                this.options.debounceDelay
            );
            
            field.addEventListener('input', inputHandler);
            field.addEventListener('keyup', inputHandler);
        }
        
        if (this.options.validateOnBlur) {
            field.addEventListener('blur', () => {
                this.validateField(field, form);
            });
        }
        
        // Special handling for different input types
        this.setupSpecialFieldHandling(field, form);
    }
    
    setupSpecialFieldHandling(field, form) {
        const fieldType = field.type || field.tagName.toLowerCase();
        
        switch (fieldType) {
            case 'file':
                field.addEventListener('change', () => {
                    this.validateFileField(field, form);
                });
                break;
                
            case 'checkbox':
            case 'radio':
                field.addEventListener('change', () => {
                    this.validateField(field, form);
                });
                break;
                
            case 'select':
            case 'select-one':
            case 'select-multiple':
                field.addEventListener('change', () => {
                    this.validateField(field, form);
                });
                break;
        }
        
        // Special handling for Markdown editors
        if (field.classList.contains('markdown-editor')) {
            this.setupMarkdownEditorValidation(field, form);
        }
    }
    
    setupMarkdownEditorValidation(field, form) {
        // Handle various Markdown editor implementations
        const editorType = field.getAttribute('data-editor-type');
        
        switch (editorType) {
            case 'codemirror':
                this.setupCodeMirrorValidation(field, form);
                break;
            case 'ace':
                this.setupAceEditorValidation(field, form);
                break;
            case 'simple':
            default:
                // Standard textarea handling
                break;
        }
    }
    
    parseFormValidationRules(form) {
        const formId = form.id;
        const rules = {
            fields: new Map(),
            crossFieldRules: [],
            customRules: []
        };
        
        // Parse form-level validation rules
        const formRules = form.getAttribute('data-validate');
        if (formRules) {
            try {
                const parsed = JSON.parse(formRules);
                rules.crossFieldRules = parsed.crossField || [];
                rules.customRules = parsed.custom || [];
            } catch (error) {
                console.warn('Failed to parse form validation rules:', error);
            }
        }
        
        this.validationRules.set(formId, rules);
    }
    
    parseFieldValidationRules(field, formId) {
        const fieldName = field.name || field.id;
        const rules = [];
        
        // Parse validation rules from data attributes
        const validationData = field.getAttribute('data-validate');
        
        if (validationData) {
            try {
                const parsed = JSON.parse(validationData);
                
                if (Array.isArray(parsed)) {
                    rules.push(...parsed);
                } else {
                    rules.push(parsed);
                }
            } catch (error) {
                // Try parsing as simple rule list
                const simpleRules = validationData.split('|');
                rules.push(...simpleRules.map(rule => {
                    const [name, ...params] = rule.split(':');
                    return {
                        rule: name.trim(),
                        params: params.length > 0 ? params.join(':') : undefined
                    };
                }));
            }
        }
        
        // Add HTML5 validation attributes
        this.addHtml5ValidationRules(field, rules);
        
        // Store rules
        const formRules = this.validationRules.get(formId);
        formRules.fields.set(fieldName, rules);
    }
    
    addHtml5ValidationRules(field, rules) {
        // Required attribute
        if (field.hasAttribute('required')) {
            rules.unshift({ rule: 'required' });
        }
        
        // Min/max length
        if (field.hasAttribute('minlength')) {
            rules.push({
                rule: 'minLength',
                params: field.getAttribute('minlength')
            });
        }
        
        if (field.hasAttribute('maxlength')) {
            rules.push({
                rule: 'maxLength',
                params: field.getAttribute('maxlength')
            });
        }
        
        // Pattern
        if (field.hasAttribute('pattern')) {
            rules.push({
                rule: 'pattern',
                params: field.getAttribute('pattern')
            });
        }
        
        // Type-specific validations
        switch (field.type) {
            case 'email':
                rules.push({ rule: 'email' });
                break;
            case 'url':
                rules.push({ rule: 'url' });
                break;
            case 'number':
                rules.push({ rule: 'number' });
                break;
        }
    }
    
    async validateField(field, form) {
        const formId = form.id;
        const fieldName = field.name || field.id;
        const formRules = this.validationRules.get(formId);
        const fieldRules = formRules?.fields.get(fieldName) || [];
        
        const validationResult = {
            valid: true,
            errors: [],
            warnings: [],
            field: fieldName,
            value: this.getFieldValue(field)
        };
        
        // Run validation rules
        for (const ruleConfig of fieldRules) {
            const ruleName = ruleConfig.rule;
            const params = ruleConfig.params;
            
            const validator = this.options.customValidators.get(ruleName);
            if (validator) {
                try {
                    const result = await validator(validationResult.value, params, field, form);
                    
                    if (!result.valid) {
                        validationResult.valid = false;
                        validationResult.errors.push({
                            rule: ruleName,
                            message: this.formatErrorMessage(ruleName, params, result.message),
                            params
                        });
                        
                        // Stop on first error if configured
                        if (ruleConfig.stopOnError !== false) {
                            break;
                        }
                    }
                    
                    if (result.warnings) {
                        validationResult.warnings.push(...result.warnings);
                    }
                } catch (error) {
                    console.error(`Validation error for rule ${ruleName}:`, error);
                    validationResult.valid = false;
                    validationResult.errors.push({
                        rule: ruleName,
                        message: 'Validation failed due to internal error',
                        params
                    });
                }
            }
        }
        
        // Store validation result
        this.validationResults.set(`${formId}.${fieldName}`, validationResult);
        
        // Update UI
        this.updateFieldValidationUI(field, validationResult);
        
        return validationResult;
    }
    
    getFieldValue(field) {
        switch (field.type) {
            case 'checkbox':
                return field.checked;
            case 'radio':
                const form = field.closest('form');
                const radioGroup = form.querySelectorAll(`input[name="${field.name}"]`);
                for (const radio of radioGroup) {
                    if (radio.checked) {
                        return radio.value;
                    }
                }
                return null;
            case 'file':
                return field.files;
            case 'select-multiple':
                return Array.from(field.selectedOptions).map(option => option.value);
            default:
                return field.value;
        }
    }
    
    // Validation rule implementations
    validateRequired(value, params, field) {
        const isEmpty = value === null || value === undefined || 
                       (typeof value === 'string' && value.trim() === '') ||
                       (Array.isArray(value) && value.length === 0) ||
                       (field.type === 'checkbox' && !value);
        
        return {
            valid: !isEmpty,
            message: isEmpty ? this.options.messages.required : null
        };
    }
    
    validateMinLength(value, params, field) {
        const minLength = parseInt(params);
        const length = typeof value === 'string' ? value.length : 0;
        const valid = length >= minLength;
        
        return {
            valid,
            message: valid ? null : this.options.messages.minLength.replace('{min}', minLength)
        };
    }
    
    validateMaxLength(value, params, field) {
        const maxLength = parseInt(params);
        const length = typeof value === 'string' ? value.length : 0;
        const valid = length <= maxLength;
        
        return {
            valid,
            message: valid ? null : this.options.messages.maxLength.replace('{max}', maxLength)
        };
    }
    
    validatePattern(value, params, field) {
        if (!value || typeof value !== 'string') {
            return { valid: true }; // Pattern validation only applies to non-empty strings
        }
        
        const pattern = new RegExp(params);
        const valid = pattern.test(value);
        
        return {
            valid,
            message: valid ? null : this.options.messages.pattern
        };
    }
    
    validateEmail(value, params, field) {
        if (!value || typeof value !== 'string') {
            return { valid: true };
        }
        
        const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        const valid = emailPattern.test(value);
        
        return {
            valid,
            message: valid ? null : this.options.messages.email
        };
    }
    
    validateUrl(value, params, field) {
        if (!value || typeof value !== 'string') {
            return { valid: true };
        }
        
        try {
            new URL(value);
            return { valid: true };
        } catch {
            return {
                valid: false,
                message: this.options.messages.url
            };
        }
    }
    
    validateNumber(value, params, field) {
        if (!value || value === '') {
            return { valid: true };
        }
        
        const num = parseFloat(value);
        const valid = !isNaN(num) && isFinite(num);
        
        return {
            valid,
            message: valid ? null : this.options.messages.number
        };
    }
    
    validateMarkdown(value, params, field) {
        if (!value || typeof value !== 'string') {
            return { valid: true };
        }
        
        const errors = [];
        const warnings = [];
        
        // Check for common Markdown syntax issues
        this.validateMarkdownSyntax(value, errors, warnings);
        
        return {
            valid: errors.length === 0,
            message: errors.length > 0 ? errors[0] : null,
            warnings: warnings
        };
    }
    
    validateMarkdownSyntax(content, errors, warnings) {
        // Check for unmatched brackets
        const openBrackets = (content.match(/\[/g) || []).length;
        const closeBrackets = (content.match(/\]/g) || []).length;
        
        if (openBrackets !== closeBrackets) {
            errors.push('Unmatched square brackets in Markdown links');
        }
        
        // Check for unmatched parentheses in links
        const linkPattern = /\[([^\]]+)\]\(([^)]+)\)/g;
        let match;
        while ((match = linkPattern.exec(content)) !== null) {
            const linkUrl = match[2];
            if (!linkUrl.trim()) {
                warnings.push(`Empty URL in link: "${match[1]}"`);
            }
        }
        
        // Check for code block consistency
        const codeBlockMatches = content.match(/```/g) || [];
        if (codeBlockMatches.length % 2 !== 0) {
            errors.push('Unmatched code block delimiters (```)');
        }
        
        // Check for heading structure
        const headings = content.match(/^#+\s+.+$/gm) || [];
        for (const heading of headings) {
            const level = heading.match(/^#+/)[0].length;
            if (level > 6) {
                warnings.push(`Heading level ${level} exceeds maximum (6)`);
            }
        }
    }
    
    validateCodeBlock(value, params, field) {
        if (!value || typeof value !== 'string') {
            return { valid: true };
        }
        
        const language = params || 'javascript';
        const errors = [];
        
        try {
            // Basic syntax validation based on language
            switch (language.toLowerCase()) {
                case 'json':
                    JSON.parse(value);
                    break;
                case 'javascript':
                case 'js':
                    // Basic JS validation - check for common syntax issues
                    this.validateJavaScriptSyntax(value, errors);
                    break;
                case 'yaml':
                case 'yml':
                    // Basic YAML validation
                    this.validateYAMLSyntax(value, errors);
                    break;
            }
        } catch (error) {
            errors.push(`${language} syntax error: ${error.message}`);
        }
        
        return {
            valid: errors.length === 0,
            message: errors.length > 0 ? errors[0] : null
        };
    }
    
    validateJavaScriptSyntax(code, errors) {
        // Basic bracket matching
        const brackets = { '(': ')', '[': ']', '{': '}' };
        const stack = [];
        
        for (let i = 0; i < code.length; i++) {
            const char = code[i];
            if (brackets[char]) {
                stack.push(char);
            } else if (Object.values(brackets).includes(char)) {
                const last = stack.pop();
                if (!last || brackets[last] !== char) {
                    errors.push(`Mismatched bracket at position ${i}`);
                    break;
                }
            }
        }
        
        if (stack.length > 0) {
            errors.push('Unclosed brackets');
        }
    }
    
    validateYAMLSyntax(yaml, errors) {
        const lines = yaml.split('\n');
        
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            
            // Check for tabs (YAML should use spaces)
            if (line.includes('\t')) {
                errors.push(`Line ${i + 1}: YAML should use spaces, not tabs`);
            }
            
            // Check for basic key-value format
            if (line.trim() && !line.trim().startsWith('#') && 
                !line.includes(':') && !line.trim().startsWith('-')) {
                errors.push(`Line ${i + 1}: Invalid YAML syntax`);
            }
        }
    }
    
    async validateAsync(value, params, field, form) {
        // Example async validation (e.g., check if username is available)
        try {
            const config = JSON.parse(params);
            const response = await fetch(config.url, {
                method: config.method || 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    ...config.headers
                },
                body: JSON.stringify({ value, field: field.name })
            });
            
            const result = await response.json();
            
            return {
                valid: result.valid,
                message: result.message || this.options.messages.async
            };
        } catch (error) {
            return {
                valid: false,
                message: 'Validation service unavailable'
            };
        }
    }
    
    validateConditional(value, params, field, form) {
        try {
            const condition = JSON.parse(params);
            const targetField = form.querySelector(`[name="${condition.field}"]`);
            
            if (!targetField) {
                return { valid: true }; // Skip if target field not found
            }
            
            const targetValue = this.getFieldValue(targetField);
            const shouldValidate = this.evaluateCondition(targetValue, condition);
            
            if (!shouldValidate) {
                return { valid: true }; // Skip validation
            }
            
            // Run nested validation
            const nestedRule = condition.rule;
            const nestedParams = condition.params;
            const validator = this.options.customValidators.get(nestedRule);
            
            if (validator) {
                return validator(value, nestedParams, field, form);
            }
            
            return { valid: true };
        } catch (error) {
            return {
                valid: false,
                message: 'Conditional validation error'
            };
        }
    }
    
    evaluateCondition(value, condition) {
        switch (condition.operator) {
            case 'equals':
                return value === condition.value;
            case 'not_equals':
                return value !== condition.value;
            case 'greater_than':
                return parseFloat(value) > parseFloat(condition.value);
            case 'less_than':
                return parseFloat(value) < parseFloat(condition.value);
            case 'contains':
                return typeof value === 'string' && value.includes(condition.value);
            case 'not_empty':
                return value !== null && value !== undefined && value !== '';
            default:
                return false;
        }
    }
    
    updateFieldValidationUI(field, validationResult) {
        // Remove existing validation classes
        field.classList.remove(this.options.errorClass, this.options.successClass);
        
        // Remove existing error messages
        const existingErrors = field.parentNode.querySelectorAll('.field-error');
        existingErrors.forEach(error => error.remove());
        
        if (validationResult.valid) {
            field.classList.add(this.options.successClass);
        } else {
            field.classList.add(this.options.errorClass);
            
            if (this.options.showErrorsInline) {
                this.displayFieldErrors(field, validationResult.errors);
            }
        }
        
        // Display warnings
        if (validationResult.warnings.length > 0) {
            this.displayFieldWarnings(field, validationResult.warnings);
        }
        
        // Update global validation summary
        this.updateValidationSummary();
    }
    
    displayFieldErrors(field, errors) {
        const errorContainer = document.createElement('div');
        errorContainer.className = 'field-error';
        
        errors.forEach(error => {
            const errorElement = document.createElement('span');
            errorElement.className = 'error-message';
            errorElement.textContent = error.message;
            errorElement.setAttribute('role', 'alert');
            errorContainer.appendChild(errorElement);
        });
        
        field.parentNode.insertBefore(errorContainer, field.nextSibling);
    }
    
    displayFieldWarnings(field, warnings) {
        const warningContainer = document.createElement('div');
        warningContainer.className = 'field-warning';
        
        warnings.forEach(warning => {
            const warningElement = document.createElement('span');
            warningElement.className = 'warning-message';
            warningElement.textContent = warning;
            warningContainer.appendChild(warningElement);
        });
        
        field.parentNode.insertBefore(warningContainer, field.nextSibling);
    }
    
    async handleFormSubmit(event) {
        event.preventDefault();
        
        const form = event.target;
        const formId = form.id;
        
        // Validate all fields
        const fields = form.querySelectorAll('[data-validate]');
        const validationPromises = Array.from(fields).map(field => 
            this.validateField(field, form)
        );
        
        const results = await Promise.all(validationPromises);
        const hasErrors = results.some(result => !result.valid);
        
        // Run cross-field validation
        const crossFieldResults = await this.validateCrossFieldRules(form);
        const hasCrossFieldErrors = crossFieldResults.some(result => !result.valid);
        
        if (hasErrors || hasCrossFieldErrors) {
            this.displayValidationSummary(form, [...results, ...crossFieldResults]);
            return false;
        }
        
        // Form is valid - proceed with submission
        this.handleValidFormSubmission(form);
        return true;
    }
    
    async validateCrossFieldRules(form) {
        const formId = form.id;
        const formRules = this.validationRules.get(formId);
        const crossFieldRules = formRules?.crossFieldRules || [];
        
        const results = [];
        
        for (const rule of crossFieldRules) {
            const result = await this.validateCrossFieldRule(form, rule);
            results.push(result);
        }
        
        return results;
    }
    
    async validateCrossFieldRule(form, rule) {
        switch (rule.type) {
            case 'match':
                return this.validateFieldsMatch(form, rule);
            case 'password_confirmation':
                return this.validatePasswordConfirmation(form, rule);
            case 'date_range':
                return this.validateDateRange(form, rule);
            default:
                return { valid: true };
        }
    }
    
    validateFieldsMatch(form, rule) {
        const field1 = form.querySelector(`[name="${rule.field1}"]`);
        const field2 = form.querySelector(`[name="${rule.field2}"]`);
        
        if (!field1 || !field2) {
            return { valid: true }; // Skip if fields not found
        }
        
        const value1 = this.getFieldValue(field1);
        const value2 = this.getFieldValue(field2);
        const valid = value1 === value2;
        
        return {
            valid,
            field: rule.field2,
            message: valid ? null : rule.message || this.options.messages.crossField
        };
    }
    
    handleValidFormSubmission(form) {
        // Collect form data
        const formData = new FormData(form);
        const data = Object.fromEntries(formData.entries());
        
        // Trigger custom submission handler if defined
        const submitHandler = form.getAttribute('data-submit-handler');
        if (submitHandler && window[submitHandler]) {
            window[submitHandler](data, form);
            return;
        }
        
        // Default submission handling
        this.submitFormData(form, data);
    }
    
    async submitFormData(form, data) {
        const submitUrl = form.action || '#';
        const method = form.method || 'POST';
        
        try {
            const response = await fetch(submitUrl, {
                method: method,
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(data)
            });
            
            if (response.ok) {
                this.displaySubmissionSuccess(form);
            } else {
                this.displaySubmissionError(form, 'Submission failed');
            }
        } catch (error) {
            this.displaySubmissionError(form, error.message);
        }
    }
    
    displaySubmissionSuccess(form) {
        const successMessage = document.createElement('div');
        successMessage.className = 'submission-success';
        successMessage.textContent = 'Form submitted successfully!';
        successMessage.setAttribute('role', 'alert');
        
        form.insertBefore(successMessage, form.firstChild);
        
        setTimeout(() => {
            successMessage.remove();
        }, 5000);
    }
    
    displaySubmissionError(form, message) {
        const errorMessage = document.createElement('div');
        errorMessage.className = 'submission-error';
        errorMessage.textContent = `Submission error: ${message}`;
        errorMessage.setAttribute('role', 'alert');
        
        form.insertBefore(errorMessage, form.firstChild);
    }
    
    formatErrorMessage(ruleName, params, customMessage) {
        if (customMessage) return customMessage;
        
        let message = this.options.messages[ruleName] || 'Validation failed';
        
        if (params && typeof params === 'string') {
            message = message.replace(/\{(\w+)\}/g, (match, key) => {
                return params[key] || match;
            });
        }
        
        return message;
    }
    
    debounce(func, delay) {
        let timeoutId;
        return (...args) => {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => func.apply(this, args), delay);
        };
    }
    
    // Public API methods
    validateForm(formId) {
        const form = document.getElementById(formId);
        if (form) {
            const submitEvent = new Event('submit', { cancelable: true });
            return this.handleFormSubmit(submitEvent);
        }
        return false;
    }
    
    getFormValidationResults(formId) {
        const results = new Map();
        
        for (const [key, result] of this.validationResults) {
            if (key.startsWith(`${formId}.`)) {
                const fieldName = key.substring(formId.length + 1);
                results.set(fieldName, result);
            }
        }
        
        return results;
    }
    
    clearValidationResults(formId) {
        const keysToRemove = [];
        
        for (const key of this.validationResults.keys()) {
            if (key.startsWith(`${formId}.`)) {
                keysToRemove.push(key);
            }
        }
        
        keysToRemove.forEach(key => this.validationResults.delete(key));
        
        // Clear UI
        const form = document.getElementById(formId);
        if (form) {
            const fields = form.querySelectorAll('[data-validate]');
            fields.forEach(field => {
                field.classList.remove(this.options.errorClass, this.options.successClass);
                const errors = field.parentNode.querySelectorAll('.field-error, .field-warning');
                errors.forEach(error => error.remove());
            });
        }
    }
}

// Usage example and initialization
document.addEventListener('DOMContentLoaded', () => {
    const validator = new MarkdownFormValidator({
        validateOnInput: true,
        validateOnBlur: true,
        debounceDelay: 300,
        showErrorsInline: true,
        
        // Custom validation messages
        messages: {
            required: 'This field is required for processing',
            email: 'Please provide a valid email address',
            markdown: 'Invalid Markdown syntax detected'
        }
    });
    
    // Add custom validators
    validator.addValidator('githubUsername', (value) => {
        if (!value) return { valid: true };
        
        const githubPattern = /^[a-zA-Z0-9]([a-zA-Z0-9]|-(?=[a-zA-Z0-9])){0,38}$/;
        const valid = githubPattern.test(value);
        
        return {
            valid,
            message: valid ? null : 'Please enter a valid GitHub username'
        };
    });
    
    validator.addValidator('markdownHeadings', (value) => {
        if (!value) return { valid: true };
        
        const headings = value.match(/^#+\s+.+$/gm) || [];
        const errors = [];
        
        // Check heading hierarchy
        let lastLevel = 0;
        for (const heading of headings) {
            const level = heading.match(/^#+/)[0].length;
            if (level > lastLevel + 1) {
                errors.push(`Heading level ${level} skips levels`);
                break;
            }
            lastLevel = level;
        }
        
        return {
            valid: errors.length === 0,
            message: errors.length > 0 ? errors[0] : null
        };
    });
    
    window.markdownFormValidator = validator;
});

Dynamic Input Processing System

Implementing real-time input processing and validation feedback:

<!-- interactive-form-example.html - Example Markdown documentation form -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Interactive Markdown Documentation Form</title>
    <link rel="stylesheet" href="form-validation-styles.css">
</head>
<body>
    <!-- Example: Markdown Content Submission Form -->
    <form id="markdown-content-form" data-validate='{"crossField":[{"type":"match","field1":"email","field2":"email_confirm","message":"Email addresses must match"}]}' class="markdown-form">
        
        <h2>Submit Markdown Content</h2>
        
        <div class="form-group">
            <label for="author-name">Author Name *</label>
            <input type="text" 
                   id="author-name" 
                   name="author" 
                   data-validate='[{"rule":"required"},{"rule":"minLength","params":"2"}]'
                   aria-describedby="author-help"
                   class="form-control">
            <div id="author-help" class="form-help">
                Enter your full name as it should appear in the documentation.
            </div>
        </div>
        
        <div class="form-group">
            <label for="author-email">Email Address *</label>
            <input type="email" 
                   id="author-email" 
                   name="email" 
                   data-validate='[{"rule":"required"},{"rule":"email"}]'
                   class="form-control">
        </div>
        
        <div class="form-group">
            <label for="email-confirm">Confirm Email *</label>
            <input type="email" 
                   id="email-confirm" 
                   name="email_confirm" 
                   data-validate='[{"rule":"required"}]'
                   class="form-control">
        </div>
        
        <div class="form-group">
            <label for="github-username">GitHub Username</label>
            <input type="text" 
                   id="github-username" 
                   name="github" 
                   data-validate='[{"rule":"githubUsername"}]'
                   class="form-control"
                   placeholder="your-username">
            <div class="form-help">
                Optional: Link your GitHub profile for attribution.
            </div>
        </div>
        
        <div class="form-group">
            <label for="content-title">Content Title *</label>
            <input type="text" 
                   id="content-title" 
                   name="title" 
                   data-validate='[{"rule":"required"},{"rule":"minLength","params":"10"},{"rule":"maxLength","params":"100"}]'
                   class="form-control"
                   placeholder="Enter a descriptive title">
        </div>
        
        <div class="form-group">
            <label for="content-category">Category *</label>
            <select id="content-category" 
                    name="category" 
                    data-validate='[{"rule":"required"}]'
                    class="form-control">
                <option value="">Select a category...</option>
                <option value="tutorial">Tutorial</option>
                <option value="guide">Guide</option>
                <option value="reference">Reference</option>
                <option value="example">Example</option>
            </select>
        </div>
        
        <div class="form-group">
            <label for="content-tags">Tags (comma-separated)</label>
            <input type="text" 
                   id="content-tags" 
                   name="tags" 
                   data-validate='[{"rule":"pattern","params":"^[a-zA-Z0-9,-\\s]+$"}]'
                   class="form-control"
                   placeholder="markdown, tutorial, documentation">
        </div>
        
        <div class="form-group">
            <label for="markdown-content">Markdown Content *</label>
            <textarea id="markdown-content" 
                      name="content" 
                      data-validate='[{"rule":"required"},{"rule":"minLength","params":"100"},{"rule":"markdown"},{"rule":"markdownHeadings"}]'
                      class="form-control markdown-editor"
                      rows="20"
                      placeholder="Enter your Markdown content here...

# Example Heading

Your content goes here with proper **formatting** and [links](http://example.com).

## Code Examples

```javascript
console.log('Hello, world!');

Remember to use proper Markdown syntax!”></textarea>
<div class="form-help">
Write your content in Markdown format. The validator will check for syntax issues and heading structure.
</div>
<div class="markdown-preview" id="markdown-preview">
<h3>Preview</h3>
<div class="preview-content" id="preview-content">
<p>Preview will appear here as you type…</p>
</div>
</div>
</div>

    <div class="form-group">
        <label for="code-language">Primary Code Language</label>
        <select id="code-language" name="code_language" class="form-control">
            <option value="">Not applicable</option>
            <option value="javascript">JavaScript</option>
            <option value="python">Python</option>
            <option value="java">Java</option>
            <option value="go">Go</option>
            <option value="rust">Rust</option>
            <option value="typescript">TypeScript</option>
        </select>
    </div>
    
    <div class="form-group">
        <label for="code-example">Code Example</label>
        <textarea id="code-example" 
                  name="code_example" 
                  data-validate='[{"rule":"codeBlock","params":"javascript"}]'
                  class="form-control code-editor"
                  rows="10"
                  placeholder="// Optional: Provide a standalone code example function exampleFunction() {
return 'Hello, Markdown!'; }"></textarea>
    </div>
    
    <div class="form-group checkbox-group">
        <label class="checkbox-label">
            <input type="checkbox" 
                   id="accept-license" 
                   name="accept_license" 
                   data-validate='[{"rule":"required"}]'
                   value="1">
            <span class="checkmark"></span>
            I agree to license this content under CC BY-SA 4.0 *
        </label>
    </div>
    
    <div class="form-group checkbox-group">
        <label class="checkbox-label">
            <input type="checkbox" 
                   id="original-content" 
                   name="original_content" 
                   data-validate='[{"rule":"required"}]'
                   value="1">
            <span class="checkmark"></span>
            I confirm this is my original work or properly attributed *
        </label>
    </div>
    
    <div class="form-actions">
        <button type="button" id="preview-btn" class="btn btn-secondary">
            Preview Content
        </button>
        <button type="submit" class="btn btn-primary">
            Submit Content
        </button>
        <button type="reset" class="btn btn-outline">
            Reset Form
        </button>
    </div>
    
    <div id="validation-summary" class="validation-summary" role="alert" aria-live="polite">
        <!-- Validation summary will appear here -->
    </div>
    
</form>

<!-- Advanced Form: Documentation Configuration -->
<form id="doc-config-form" data-validate class="markdown-form config-form">
    
    <h2>Documentation Configuration</h2>
    
    <div class="form-group">
        <label for="site-title">Site Title *</label>
        <input type="text" 
               id="site-title" 
               name="site_title" 
               data-validate='[{"rule":"required"},{"rule":"maxLength","params":"50"}]'
               class="form-control">
    </div>
    
    <div class="form-group">
        <label for="base-url">Base URL *</label>
        <input type="url" 
               id="base-url" 
               name="base_url" 
               data-validate='[{"rule":"required"},{"rule":"url"}]'
               class="form-control"
               placeholder="https://docs.example.com">
    </div>
    
    <div class="form-group">
        <label for="theme-config">Theme Configuration (JSON)</label>
        <textarea id="theme-config" 
                  name="theme_config" 
                  data-validate='[{"rule":"codeBlock","params":"json"}]'
                  class="form-control code-editor"
                  rows="15"
                  placeholder='{   "colors": {
"primary": "#007cba",
"secondary": "#6c757d"   },   "fonts": {
"body": "Inter, sans-serif",
"heading": "Poppins, sans-serif",
"code": "JetBrains Mono, monospace"   },   "layout": {
"sidebar_width": 280,
"max_content_width": 1200   } }'></textarea>
        <div class="form-help">
            Configure theme settings in JSON format. Invalid JSON will be highlighted.
        </div>
    </div>
    
    <div class="form-group">
        <label for="build-command">Build Command</label>
        <input type="text" 
               id="build-command" 
               name="build_command" 
               class="form-control"
               placeholder="npm run build"
               value="npm run build">
    </div>
    
    <div class="form-group">
        <fieldset>
            <legend>Features</legend>
            <div class="checkbox-group">
                <label class="checkbox-label">
                    <input type="checkbox" name="features" value="search">
                    <span class="checkmark"></span>
                    Enable Search
                </label>
            </div>
            <div class="checkbox-group">
                <label class="checkbox-label">
                    <input type="checkbox" name="features" value="analytics">
                    <span class="checkmark"></span>
                    Analytics Integration
                </label>
            </div>
            <div class="checkbox-group">
                <label class="checkbox-label">
                    <input type="checkbox" name="features" value="comments">
                    <span class="checkmark"></span>
                    Comment System
                </label>
            </div>
        </fieldset>
    </div>
    
    <div class="form-actions">
        <button type="submit" class="btn btn-primary">
            Save Configuration
        </button>
        <button type="button" id="validate-config" class="btn btn-secondary">
            Validate Only
        </button>
    </div>
    
</form>

<script src="form-validator.js"></script>
<script src="markdown-preview.js"></script>
<script>
    // Enhanced form interaction
    document.addEventListener('DOMContentLoaded', () => {
        // Setup markdown preview
        const markdownContent = document.getElementById('markdown-content');
        const previewContent = document.getElementById('preview-content');
        
        if (markdownContent && previewContent) {
            markdownContent.addEventListener('input', debounce(() => {
                updateMarkdownPreview(markdownContent.value, previewContent);
            }, 500));
        }
        
        // Preview button handler
        document.getElementById('preview-btn')?.addEventListener('click', () => {
            const content = markdownContent.value;
            if (content.trim()) {
                openMarkdownPreview(content);
            }
        });
        
        // Config validation button
        document.getElementById('validate-config')?.addEventListener('click', () => {
            window.markdownFormValidator.validateForm('doc-config-form');
        });
    });
    
    function updateMarkdownPreview(markdown, container) {
        // Simple markdown to HTML conversion (in real implementation, use a proper parser)
        let html = markdown
            .replace(/^# (.+)$/gm, '<h1>$1</h1>')
            .replace(/^## (.+)$/gm, '<h2>$1</h2>')
            .replace(/^### (.+)$/gm, '<h3>$1</h3>')
            .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
            .replace(/\*(.+?)\*/g, '<em>$1</em>')
            .replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank">$1</a>')
            .replace(/```([\s\S]*?)```/g, '<pre><code>$1</code></pre>')
            .replace(/`(.+?)`/g, '<code>$1</code>')
            .replace(/\n/g, '<br>');
            
        container.innerHTML = html || '<p><em>Preview will appear here as you type...</em></p>';
    }
    
    function openMarkdownPreview(content) {
        const previewWindow = window.open('', '_blank', 'width=800,height=600');
        previewWindow.document.write(`
            <!DOCTYPE html>
            <html>
            <head>
                <title>Markdown Preview</title>
                <style>
                    body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; line-height: 1.6; max-width: 800px; margin: 0 auto; padding: 2rem; }
                    code { background: #f6f8fa; padding: 0.2em 0.4em; border-radius: 3px; }
                    pre { background: #f6f8fa; padding: 1rem; border-radius: 6px; overflow: auto; }
                    blockquote { border-left: 4px solid #dfe2e5; margin: 0; padding-left: 1rem; color: #666; }
                </style>
            </head>
            <body>
                ${updateMarkdownPreview(content, { innerHTML: '' }).innerHTML || content}
            </body>
            </html>
        `);
    }
    
    function debounce(func, wait) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func(...args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }
</script>

</body>
</html>


## Advanced Input Processing Techniques

### Real-Time Content Analysis

Implementing sophisticated content analysis and validation for Markdown input:

```javascript
// content-analyzer.js - Advanced content analysis for Markdown forms
class MarkdownContentAnalyzer {
    constructor(options = {}) {
        this.options = {
            enableReadabilityAnalysis: true,
            enableSEOAnalysis: true,
            enableAccessibilityCheck: true,
            enableContentQualityMetrics: true,
            realTimeAnalysis: true,
            analysisDebounceDelay: 1000,
            ...options
        };
        
        this.analysisCache = new Map();
        this.analysisHistory = [];
        this.qualityThresholds = {
            readability: 60,
            seo: 70,
            accessibility: 80,
            overall: 70
        };
    }
    
    async analyzeContent(content, context = {}) {
        if (!content || typeof content !== 'string') {
            return this.createEmptyAnalysis();
        }
        
        const cacheKey = this.generateCacheKey(content, context);
        
        if (this.analysisCache.has(cacheKey)) {
            return this.analysisCache.get(cacheKey);
        }
        
        const analysis = {
            timestamp: new Date().toISOString(),
            content: {
                length: content.length,
                wordCount: this.countWords(content),
                paragraphCount: this.countParagraphs(content),
                sentenceCount: this.countSentences(content)
            },
            structure: this.analyzeStructure(content),
            readability: this.options.enableReadabilityAnalysis ? 
                this.analyzeReadability(content) : null,
            seo: this.options.enableSEOAnalysis ? 
                this.analyzeSEO(content, context) : null,
            accessibility: this.options.enableAccessibilityCheck ? 
                this.analyzeAccessibility(content) : null,
            quality: this.analyzeContentQuality(content),
            issues: [],
            suggestions: []
        };
        
        // Calculate overall score
        analysis.overallScore = this.calculateOverallScore(analysis);
        
        // Generate issues and suggestions
        this.generateContentFeedback(analysis);
        
        // Cache the result
        this.analysisCache.set(cacheKey, analysis);
        
        // Add to history
        this.analysisHistory.push({
            timestamp: analysis.timestamp,
            contentLength: analysis.content.length,
            score: analysis.overallScore
        });
        
        // Keep history limited
        if (this.analysisHistory.length > 100) {
            this.analysisHistory = this.analysisHistory.slice(-50);
        }
        
        return analysis;
    }
    
    analyzeStructure(content) {
        const structure = {
            headings: [],
            codeBlocks: [],
            links: [],
            images: [],
            lists: [],
            tables: []
        };
        
        // Extract headings
        const headingMatches = content.matchAll(/^(#{1,6})\s+(.+)$/gm);
        for (const match of headingMatches) {
            structure.headings.push({
                level: match[1].length,
                text: match[2],
                line: this.getLineNumber(content, match.index)
            });
        }
        
        // Extract code blocks
        const codeBlockMatches = content.matchAll(/```(\w+)?\n([\s\S]*?)```/g);
        for (const match of codeBlockMatches) {
            structure.codeBlocks.push({
                language: match[1] || 'plain',
                code: match[2],
                line: this.getLineNumber(content, match.index)
            });
        }
        
        // Extract links
        const linkMatches = content.matchAll(/\[([^\]]+)\]\(([^)]+)\)/g);
        for (const match of linkMatches) {
            structure.links.push({
                text: match[1],
                url: match[2],
                isExternal: this.isExternalLink(match[2]),
                line: this.getLineNumber(content, match.index)
            });
        }
        
        // Extract images
        const imageMatches = content.matchAll(/!\[([^\]]*)\]\(([^)]+)\)/g);
        for (const match of imageMatches) {
            structure.images.push({
                alt: match[1],
                src: match[2],
                line: this.getLineNumber(content, match.index)
            });
        }
        
        return structure;
    }
    
    analyzeReadability(content) {
        // Clean content for readability analysis
        const cleanContent = this.cleanContentForAnalysis(content);
        
        const words = this.countWords(cleanContent);
        const sentences = this.countSentences(cleanContent);
        const syllables = this.countSyllables(cleanContent);
        
        // Calculate Flesch Reading Ease
        const fleschScore = this.calculateFleschScore(words, sentences, syllables);
        
        // Calculate Flesch-Kincaid Grade Level
        const gradeLevel = this.calculateGradeLevel(words, sentences, syllables);
        
        // Analyze sentence complexity
        const sentenceAnalysis = this.analyzeSentenceComplexity(cleanContent);
        
        return {
            fleschScore: Math.round(fleschScore),
            gradeLevel: Math.round(gradeLevel * 10) / 10,
            readingLevel: this.getReadingLevel(fleschScore),
            averageWordsPerSentence: Math.round((words / sentences) * 10) / 10,
            averageSyllablesPerWord: Math.round((syllables / words) * 100) / 100,
            sentenceComplexity: sentenceAnalysis,
            recommendations: this.generateReadabilityRecommendations(fleschScore, gradeLevel)
        };
    }
    
    analyzeSEO(content, context) {
        const analysis = {
            titleOptimization: this.analyzeTitleSEO(content, context),
            headingStructure: this.analyzeHeadingSEO(content),
            keywordDensity: this.analyzeKeywordDensity(content, context.keywords),
            linkAnalysis: this.analyzeLinkSEO(content),
            contentLength: this.analyzeContentLengthSEO(content),
            suggestions: []
        };
        
        analysis.score = this.calculateSEOScore(analysis);
        return analysis;
    }
    
    analyzeAccessibility(content) {
        const issues = [];
        const suggestions = [];
        
        // Check image alt text
        const structure = this.analyzeStructure(content);
        structure.images.forEach((image, index) => {
            if (!image.alt || image.alt.trim() === '') {
                issues.push({
                    type: 'missing_alt_text',
                    severity: 'high',
                    line: image.line,
                    message: 'Image missing alt text for screen readers'
                });
            } else if (image.alt.length > 125) {
                suggestions.push({
                    type: 'long_alt_text',
                    line: image.line,
                    message: 'Alt text is quite long - consider shortening for better accessibility'
                });
            }
        });
        
        // Check heading hierarchy
        let lastLevel = 0;
        structure.headings.forEach((heading, index) => {
            if (heading.level > lastLevel + 1 && lastLevel > 0) {
                issues.push({
                    type: 'heading_hierarchy',
                    severity: 'medium',
                    line: heading.line,
                    message: `Heading level ${heading.level} skips levels (previous was ${lastLevel})`
                });
            }
            lastLevel = heading.level;
        });
        
        // Check link text
        structure.links.forEach((link, index) => {
            const linkText = link.text.toLowerCase();
            const genericTerms = ['click here', 'read more', 'more', 'here', 'link'];
            
            if (genericTerms.some(term => linkText.includes(term))) {
                suggestions.push({
                    type: 'generic_link_text',
                    line: link.line,
                    message: 'Consider using more descriptive link text'
                });
            }
        });
        
        return {
            score: this.calculateAccessibilityScore(issues, suggestions),
            issues,
            suggestions,
            summary: {
                totalIssues: issues.length,
                highSeverityIssues: issues.filter(i => i.severity === 'high').length,
                mediumSeverityIssues: issues.filter(i => i.severity === 'medium').length
            }
        };
    }
    
    analyzeContentQuality(content) {
        const quality = {
            metrics: {},
            scores: {},
            recommendations: []
        };
        
        // Content depth analysis
        const structure = this.analyzeStructure(content);
        quality.metrics.structuralDepth = this.calculateStructuralDepth(structure);
        
        // Information density
        quality.metrics.informationDensity = this.calculateInformationDensity(content);
        
        // Code-to-text ratio (important for technical documentation)
        quality.metrics.codeToTextRatio = this.calculateCodeToTextRatio(content, structure);
        
        // Link diversity
        quality.metrics.linkDiversity = this.calculateLinkDiversity(structure.links);
        
        // Content freshness indicators
        quality.metrics.freshnessIndicators = this.analyzeFreshnessIndicators(content);
        
        // Calculate individual scores
        quality.scores.depth = this.scoreStructuralDepth(quality.metrics.structuralDepth);
        quality.scores.density = this.scoreInformationDensity(quality.metrics.informationDensity);
        quality.scores.balance = this.scoreCodeToTextRatio(quality.metrics.codeToTextRatio);
        quality.scores.engagement = this.scoreLinkDiversity(quality.metrics.linkDiversity);
        
        // Overall quality score
        quality.overallScore = Object.values(quality.scores).reduce((sum, score) => sum + score, 0) / Object.keys(quality.scores).length;
        
        return quality;
    }
    
    generateContentFeedback(analysis) {
        const issues = [];
        const suggestions = [];
        
        // Content length feedback
        if (analysis.content.wordCount < 300) {
            issues.push({
                type: 'content_length',
                severity: 'medium',
                message: 'Content appears quite short. Consider expanding with more details or examples.'
            });
        } else if (analysis.content.wordCount > 3000) {
            suggestions.push({
                type: 'content_length',
                message: 'Content is quite lengthy. Consider breaking into multiple sections or pages.'
            });
        }
        
        // Heading structure feedback
        if (analysis.structure.headings.length === 0) {
            issues.push({
                type: 'structure',
                severity: 'medium',
                message: 'No headings found. Adding headings improves readability and navigation.'
            });
        }
        
        // Code examples feedback
        if (analysis.structure.codeBlocks.length === 0 && analysis.content.wordCount > 500) {
            suggestions.push({
                type: 'engagement',
                message: 'Consider adding code examples to illustrate concepts.'
            });
        }
        
        // Link analysis feedback
        const externalLinks = analysis.structure.links.filter(link => link.isExternal);
        if (externalLinks.length > analysis.structure.links.length * 0.8) {
            suggestions.push({
                type: 'links',
                message: 'High ratio of external links. Consider adding internal cross-references.'
            });
        }
        
        // Readability feedback
        if (analysis.readability && analysis.readability.fleschScore < 30) {
            issues.push({
                type: 'readability',
                severity: 'medium',
                message: 'Content may be difficult to read. Consider shorter sentences and simpler words.'
            });
        }
        
        analysis.issues = issues;
        analysis.suggestions = suggestions;
    }
    
    // Utility methods for analysis calculations
    countWords(text) {
        return text.trim().split(/\s+/).filter(word => word.length > 0).length;
    }
    
    countSentences(text) {
        return text.split(/[.!?]+/).filter(sentence => sentence.trim().length > 0).length;
    }
    
    countParagraphs(text) {
        return text.split(/\n\s*\n/).filter(para => para.trim().length > 0).length;
    }
    
    countSyllables(text) {
        const words = text.toLowerCase().match(/[a-z]+/g) || [];
        return words.reduce((total, word) => {
            let syllables = word.match(/[aeiouy]+/g) || [];
            if (word.endsWith('e')) syllables = syllables.slice(0, -1);
            return total + Math.max(1, syllables.length);
        }, 0);
    }
    
    calculateFleschScore(words, sentences, syllables) {
        return 206.835 - (1.015 * (words / sentences)) - (84.6 * (syllables / words));
    }
    
    calculateGradeLevel(words, sentences, syllables) {
        return (0.39 * (words / sentences)) + (11.8 * (syllables / words)) - 15.59;
    }
    
    getReadingLevel(fleschScore) {
        if (fleschScore >= 90) return 'Very Easy';
        if (fleschScore >= 80) return 'Easy';
        if (fleschScore >= 70) return 'Fairly Easy';
        if (fleschScore >= 60) return 'Standard';
        if (fleschScore >= 50) return 'Fairly Difficult';
        if (fleschScore >= 30) return 'Difficult';
        return 'Very Difficult';
    }
    
    cleanContentForAnalysis(content) {
        return content
            .replace(/```[\s\S]*?```/g, '') // Remove code blocks
            .replace(/`[^`]+`/g, '') // Remove inline code
            .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Extract link text
            .replace(/!\[[^\]]*\]\([^)]+\)/g, '') // Remove images
            .replace(/[#*_\-+>]/g, '') // Remove markdown formatting
            .replace(/\s+/g, ' ') // Normalize whitespace
            .trim();
    }
    
    generateCacheKey(content, context) {
        const contextString = JSON.stringify(context);
        return `${content.length}-${this.simpleHash(content + contextString)}`;
    }
    
    simpleHash(str) {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash = hash & hash; // Convert to 32bit integer
        }
        return Math.abs(hash);
    }
    
    getLineNumber(content, index) {
        return content.substring(0, index).split('\n').length;
    }
    
    isExternalLink(url) {
        return url.startsWith('http') || url.startsWith('//');
    }
    
    calculateOverallScore(analysis) {
        const scores = [];
        
        if (analysis.readability) {
            scores.push(Math.min(100, Math.max(0, analysis.readability.fleschScore)));
        }
        
        if (analysis.seo) {
            scores.push(analysis.seo.score);
        }
        
        if (analysis.accessibility) {
            scores.push(analysis.accessibility.score);
        }
        
        if (analysis.quality) {
            scores.push(analysis.quality.overallScore);
        }
        
        return scores.length > 0 ? 
            scores.reduce((sum, score) => sum + score, 0) / scores.length : 0;
    }
    
    createEmptyAnalysis() {
        return {
            timestamp: new Date().toISOString(),
            content: { length: 0, wordCount: 0, paragraphCount: 0, sentenceCount: 0 },
            structure: { headings: [], codeBlocks: [], links: [], images: [], lists: [], tables: [] },
            readability: null,
            seo: null,
            accessibility: null,
            quality: null,
            overallScore: 0,
            issues: [],
            suggestions: []
        };
    }
    
    // Public API methods
    async analyzeInRealTime(element, context = {}) {
        if (!this.options.realTimeAnalysis) return;
        
        const content = element.value || element.textContent;
        const analysis = await this.analyzeContent(content, context);
        
        this.displayAnalysisResults(element, analysis);
        return analysis;
    }
    
    displayAnalysisResults(element, analysis) {
        // Create or update analysis display
        let analysisDisplay = element.nextElementSibling;
        
        if (!analysisDisplay || !analysisDisplay.classList.contains('content-analysis')) {
            analysisDisplay = document.createElement('div');
            analysisDisplay.className = 'content-analysis';
            element.parentNode.insertBefore(analysisDisplay, element.nextSibling);
        }
        
        analysisDisplay.innerHTML = this.generateAnalysisHTML(analysis);
    }
    
    generateAnalysisHTML(analysis) {
        const scoreClass = this.getScoreClass(analysis.overallScore);
        
        return `
            <div class="analysis-summary">
                <div class="score-indicator ${scoreClass}">
                    <span class="score">${Math.round(analysis.overallScore)}</span>
                    <span class="label">Overall Score</span>
                </div>
                
                <div class="metrics">
                    <div class="metric">
                        <span class="value">${analysis.content.wordCount}</span>
                        <span class="label">Words</span>
                    </div>
                    <div class="metric">
                        <span class="value">${analysis.structure.headings.length}</span>
                        <span class="label">Headings</span>
                    </div>
                    <div class="metric">
                        <span class="value">${analysis.structure.links.length}</span>
                        <span class="label">Links</span>
                    </div>
                </div>
            </div>
            
            ${analysis.readability ? `
                <div class="readability-info">
                    <strong>Readability:</strong> ${analysis.readability.readingLevel} 
                    (Grade ${analysis.readability.gradeLevel})
                </div>
            ` : ''}
            
            ${analysis.issues.length > 0 ? `
                <div class="issues">
                    <h4>Issues to Address:</h4>
                    <ul>
                        ${analysis.issues.map(issue => `
                            <li class="issue ${issue.severity}">${issue.message}</li>
                        `).join('')}
                    </ul>
                </div>
            ` : ''}
            
            ${analysis.suggestions.length > 0 ? `
                <div class="suggestions">
                    <h4>Suggestions:</h4>
                    <ul>
                        ${analysis.suggestions.map(suggestion => `
                            <li class="suggestion">${suggestion.message}</li>
                        `).join('')}
                    </ul>
                </div>
            ` : ''}
        `;
    }
    
    getScoreClass(score) {
        if (score >= 80) return 'excellent';
        if (score >= 70) return 'good';
        if (score >= 60) return 'fair';
        return 'needs-improvement';
    }
}

// Initialize content analyzer with form validator
document.addEventListener('DOMContentLoaded', () => {
    const contentAnalyzer = new MarkdownContentAnalyzer({
        realTimeAnalysis: true,
        analysisDebounceDelay: 1500
    });
    
    // Setup real-time analysis for markdown content areas
    const markdownFields = document.querySelectorAll('.markdown-editor');
    
    markdownFields.forEach(field => {
        let analysisTimeout;
        
        field.addEventListener('input', () => {
            clearTimeout(analysisTimeout);
            analysisTimeout = setTimeout(async () => {
                const context = {
                    keywords: field.getAttribute('data-keywords')?.split(',') || [],
                    category: field.form?.querySelector('[name="category"]')?.value
                };
                
                await contentAnalyzer.analyzeInRealTime(field, context);
            }, contentAnalyzer.options.analysisDebounceDelay);
        });
    });
    
    window.markdownContentAnalyzer = contentAnalyzer;
});

Integration with Documentation Systems

Advanced form validation and input handling integrates seamlessly with modern documentation workflows. When combined with automated content validation systems, form validation ensures that user-submitted content meets quality standards and integrates properly with existing documentation structures while maintaining consistency across collaborative editing environments.

For comprehensive content management, form validation complements workflow automation systems by providing structured data collection interfaces that feed into automated processing pipelines, enabling seamless content creation workflows that maintain quality while reducing manual oversight requirements.

When building interactive documentation platforms, form validation works effectively with dynamic content generation systems by providing validated input data that can be safely processed and integrated into generated content, ensuring that user contributions enhance rather than compromise documentation quality and consistency.

Advanced Validation Strategies

Multi-Step Form Validation

Implementing progressive validation for complex documentation workflows:

// multi-step-validator.js - Advanced multi-step form validation system
class MultiStepFormValidator {
    constructor(formElement, options = {}) {
        this.form = formElement;
        this.options = {
            saveProgress: true,
            validateStepOnNext: true,
            allowStepSkipping: false,
            progressIndicator: true,
            autoSaveInterval: 30000, // 30 seconds
            ...options
        };
        
        this.steps = [];
        this.currentStep = 0;
        this.stepData = new Map();
        this.validationHistory = [];
        this.autoSaveTimer = null;
        
        this.init();
    }
    
    init() {
        this.parseFormSteps();
        this.setupProgressIndicator();
        this.setupStepNavigation();
        this.setupAutoSave();
        this.loadSavedProgress();
        
        // Show first step
        this.showStep(0);
    }
    
    parseFormSteps() {
        const stepElements = this.form.querySelectorAll('[data-step]');
        
        stepElements.forEach((element, index) => {
            const stepData = {
                element: element,
                index: index,
                title: element.getAttribute('data-step-title') || `Step ${index + 1}`,
                description: element.getAttribute('data-step-description') || '',
                required: element.hasAttribute('data-step-required'),
                fields: Array.from(element.querySelectorAll('[data-validate]')),
                validationRules: this.parseStepValidationRules(element),
                isValid: false,
                isCompleted: false
            };
            
            this.steps.push(stepData);
        });
        
        console.log(`Initialized ${this.steps.length} form steps`);
    }
    
    parseStepValidationRules(stepElement) {
        const rules = {
            requiredFields: [],
            customValidations: [],
            dependencies: []
        };
        
        // Parse step-level validation rules
        const validationData = stepElement.getAttribute('data-step-validation');
        if (validationData) {
            try {
                const parsed = JSON.parse(validationData);
                Object.assign(rules, parsed);
            } catch (error) {
                console.warn('Failed to parse step validation rules:', error);
            }
        }
        
        // Identify required fields
        rules.requiredFields = Array.from(stepElement.querySelectorAll('[required], [data-validate*="required"]'))
            .map(field => field.name || field.id);
        
        return rules;
    }
    
    setupProgressIndicator() {
        if (!this.options.progressIndicator) return;
        
        const progressContainer = document.createElement('div');
        progressContainer.className = 'form-progress';
        
        const progressBar = document.createElement('div');
        progressBar.className = 'progress-bar';
        progressBar.innerHTML = `
            <div class="progress-fill" style="width: 0%"></div>
        `;
        
        const stepIndicators = document.createElement('div');
        stepIndicators.className = 'step-indicators';
        
        this.steps.forEach((step, index) => {
            const indicator = document.createElement('div');
            indicator.className = 'step-indicator';
            indicator.setAttribute('data-step', index);
            indicator.innerHTML = `
                <div class="step-number">${index + 1}</div>
                <div class="step-title">${step.title}</div>
            `;
            
            if (index === 0) {
                indicator.classList.add('active');
            }
            
            stepIndicators.appendChild(indicator);
        });
        
        progressContainer.appendChild(progressBar);
        progressContainer.appendChild(stepIndicators);
        
        this.form.insertBefore(progressContainer, this.form.firstChild);
        
        this.progressBar = progressBar.querySelector('.progress-fill');
        this.stepIndicators = stepIndicators;
    }
    
    setupStepNavigation() {
        // Create navigation buttons
        const navContainer = document.createElement('div');
        navContainer.className = 'step-navigation';
        
        navContainer.innerHTML = `
            <button type="button" class="btn btn-secondary" id="prev-step">
                Previous
            </button>
            <button type="button" class="btn btn-primary" id="next-step">
                Next
            </button>
            <button type="submit" class="btn btn-success" id="submit-form" style="display: none;">
                Submit
            </button>
        `;
        
        this.form.appendChild(navContainer);
        
        // Setup event listeners
        this.prevButton = navContainer.querySelector('#prev-step');
        this.nextButton = navContainer.querySelector('#next-step');
        this.submitButton = navContainer.querySelector('#submit-form');
        
        this.prevButton.addEventListener('click', () => this.goToPreviousStep());
        this.nextButton.addEventListener('click', () => this.goToNextStep());
        
        // Handle form submission
        this.form.addEventListener('submit', (event) => {
            event.preventDefault();
            this.handleFormSubmission();
        });
        
        this.updateNavigationButtons();
    }
    
    setupAutoSave() {
        if (!this.options.saveProgress) return;
        
        this.autoSaveTimer = setInterval(() => {
            this.saveProgress();
        }, this.options.autoSaveInterval);
        
        // Save on form field changes
        this.form.addEventListener('input', this.debounce(() => {
            this.saveProgress();
        }, 2000));
    }
    
    async showStep(stepIndex) {
        if (stepIndex < 0 || stepIndex >= this.steps.length) return;
        
        // Hide all steps
        this.steps.forEach(step => {
            step.element.style.display = 'none';
            step.element.classList.remove('active');
        });
        
        // Show current step
        const currentStep = this.steps[stepIndex];
        currentStep.element.style.display = 'block';
        currentStep.element.classList.add('active');
        
        this.currentStep = stepIndex;
        
        // Update progress indicator
        this.updateProgressIndicator();
        this.updateNavigationButtons();
        
        // Focus first field in step
        const firstField = currentStep.element.querySelector('input, textarea, select');
        if (firstField) {
            firstField.focus();
        }
        
        // Trigger step change event
        this.form.dispatchEvent(new CustomEvent('stepChange', {
            detail: {
                stepIndex,
                step: currentStep,
                direction: stepIndex > (this.previousStep || 0) ? 'forward' : 'backward'
            }
        }));
        
        this.previousStep = stepIndex;
    }
    
    async goToNextStep() {
        if (this.options.validateStepOnNext) {
            const isValid = await this.validateCurrentStep();
            if (!isValid) return;
        }
        
        if (this.currentStep < this.steps.length - 1) {
            await this.showStep(this.currentStep + 1);
        }
    }
    
    async goToPreviousStep() {
        if (this.currentStep > 0) {
            await this.showStep(this.currentStep - 1);
        }
    }
    
    async validateCurrentStep() {
        const step = this.steps[this.currentStep];
        const validationResults = [];
        
        // Validate all fields in current step
        for (const field of step.fields) {
            if (window.markdownFormValidator) {
                const result = await window.markdownFormValidator.validateField(field, this.form);
                validationResults.push(result);
            }
        }
        
        // Run step-specific validations
        const stepValidationResult = await this.runStepValidations(step);
        validationResults.push(stepValidationResult);
        
        const isValid = validationResults.every(result => result.valid);
        step.isValid = isValid;
        
        if (isValid) {
            step.isCompleted = true;
            this.markStepAsCompleted(this.currentStep);
        } else {
            this.markStepAsIncomplete(this.currentStep);
        }
        
        return isValid;
    }
    
    async runStepValidations(step) {
        const validationResult = { valid: true, errors: [] };
        
        // Check required fields
        for (const fieldName of step.validationRules.requiredFields) {
            const field = step.element.querySelector(`[name="${fieldName}"]`);
            if (field) {
                const value = this.getFieldValue(field);
                if (this.isEmpty(value)) {
                    validationResult.valid = false;
                    validationResult.errors.push({
                        field: fieldName,
                        message: `${fieldName} is required`
                    });
                }
            }
        }
        
        // Run custom validations
        for (const customValidation of step.validationRules.customValidations) {
            try {
                const result = await this.runCustomValidation(customValidation, step);
                if (!result.valid) {
                    validationResult.valid = false;
                    validationResult.errors.push(...result.errors);
                }
            } catch (error) {
                console.error('Custom validation error:', error);
                validationResult.valid = false;
                validationResult.errors.push({
                    message: 'Validation failed due to internal error'
                });
            }
        }
        
        return validationResult;
    }
    
    async runCustomValidation(validation, step) {
        // Example custom validations
        switch (validation.type) {
            case 'markdown_content_quality':
                return await this.validateMarkdownQuality(validation, step);
            case 'file_upload_requirements':
                return await this.validateFileUploads(validation, step);
            case 'content_uniqueness':
                return await this.validateContentUniqueness(validation, step);
            default:
                return { valid: true, errors: [] };
        }
    }
    
    async validateMarkdownQuality(validation, step) {
        const markdownField = step.element.querySelector('.markdown-editor');
        if (!markdownField) return { valid: true, errors: [] };
        
        const content = markdownField.value;
        const errors = [];
        
        // Check minimum content requirements
        const wordCount = content.trim().split(/\s+/).length;
        if (wordCount < (validation.minWords || 100)) {
            errors.push({
                field: markdownField.name,
                message: `Content must be at least ${validation.minWords || 100} words`
            });
        }
        
        // Check for required elements
        if (validation.requireHeadings && !content.match(/^#+\s+/m)) {
            errors.push({
                field: markdownField.name,
                message: 'Content must include at least one heading'
            });
        }
        
        if (validation.requireCodeExamples && !content.match(/```[\s\S]*?```/)) {
            errors.push({
                field: markdownField.name,
                message: 'Content should include code examples'
            });
        }
        
        return { valid: errors.length === 0, errors };
    }
    
    updateProgressIndicator() {
        if (!this.progressBar) return;
        
        const progressPercentage = ((this.currentStep + 1) / this.steps.length) * 100;
        this.progressBar.style.width = `${progressPercentage}%`;
        
        // Update step indicators
        const indicators = this.stepIndicators.querySelectorAll('.step-indicator');
        indicators.forEach((indicator, index) => {
            indicator.classList.remove('active', 'completed');
            
            if (index === this.currentStep) {
                indicator.classList.add('active');
            } else if (index < this.currentStep || this.steps[index].isCompleted) {
                indicator.classList.add('completed');
            }
        });
    }
    
    updateNavigationButtons() {
        this.prevButton.style.display = this.currentStep > 0 ? 'inline-block' : 'none';
        this.nextButton.style.display = this.currentStep < this.steps.length - 1 ? 'inline-block' : 'none';
        this.submitButton.style.display = this.currentStep === this.steps.length - 1 ? 'inline-block' : 'none';
    }
    
    markStepAsCompleted(stepIndex) {
        const indicator = this.stepIndicators.querySelector(`[data-step="${stepIndex}"]`);
        if (indicator) {
            indicator.classList.add('completed');
        }
    }
    
    markStepAsIncomplete(stepIndex) {
        const indicator = this.stepIndicators.querySelector(`[data-step="${stepIndex}"]`);
        if (indicator) {
            indicator.classList.remove('completed');
        }
    }
    
    async handleFormSubmission() {
        // Validate all steps
        for (let i = 0; i < this.steps.length; i++) {
            await this.showStep(i);
            const isValid = await this.validateCurrentStep();
            
            if (!isValid && this.steps[i].required) {
                alert(`Please complete Step ${i + 1}: ${this.steps[i].title}`);
                return;
            }
        }
        
        // Collect all form data
        const formData = this.collectAllFormData();
        
        // Submit the form
        await this.submitForm(formData);
    }
    
    collectAllFormData() {
        const formData = new FormData(this.form);
        const data = {};
        
        for (const [key, value] of formData.entries()) {
            if (data[key]) {
                if (Array.isArray(data[key])) {
                    data[key].push(value);
                } else {
                    data[key] = [data[key], value];
                }
            } else {
                data[key] = value;
            }
        }
        
        return data;
    }
    
    async submitForm(data) {
        try {
            const response = await fetch(this.form.action || '/submit', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(data)
            });
            
            if (response.ok) {
                this.handleSubmissionSuccess();
                this.clearSavedProgress();
            } else {
                this.handleSubmissionError(await response.text());
            }
        } catch (error) {
            this.handleSubmissionError(error.message);
        }
    }
    
    handleSubmissionSuccess() {
        // Show success message
        const successDiv = document.createElement('div');
        successDiv.className = 'submission-success';
        successDiv.innerHTML = `
            <h3>✅ Form Submitted Successfully!</h3>
            <p>Thank you for your submission. We'll review it shortly.</p>
        `;
        
        this.form.innerHTML = '';
        this.form.appendChild(successDiv);
    }
    
    handleSubmissionError(errorMessage) {
        alert(`Submission failed: ${errorMessage}`);
    }
    
    saveProgress() {
        if (!this.options.saveProgress) return;
        
        const progressData = {
            currentStep: this.currentStep,
            formData: this.collectAllFormData(),
            completedSteps: this.steps.map(step => step.isCompleted),
            timestamp: new Date().toISOString()
        };
        
        localStorage.setItem(`form-progress-${this.form.id}`, JSON.stringify(progressData));
    }
    
    loadSavedProgress() {
        if (!this.options.saveProgress) return;
        
        const savedData = localStorage.getItem(`form-progress-${this.form.id}`);
        if (!savedData) return;
        
        try {
            const progressData = JSON.parse(savedData);
            
            // Restore form data
            for (const [fieldName, value] of Object.entries(progressData.formData)) {
                const field = this.form.querySelector(`[name="${fieldName}"]`);
                if (field) {
                    if (field.type === 'checkbox' || field.type === 'radio') {
                        field.checked = field.value === value;
                    } else {
                        field.value = value;
                    }
                }
            }
            
            // Restore completed steps
            progressData.completedSteps.forEach((isCompleted, index) => {
                this.steps[index].isCompleted = isCompleted;
            });
            
            // Go to saved step
            this.showStep(progressData.currentStep);
            
            console.log('Restored form progress from', progressData.timestamp);
        } catch (error) {
            console.warn('Failed to load saved progress:', error);
        }
    }
    
    clearSavedProgress() {
        localStorage.removeItem(`form-progress-${this.form.id}`);
    }
    
    // Utility methods
    getFieldValue(field) {
        switch (field.type) {
            case 'checkbox':
                return field.checked;
            case 'radio':
                const radioGroup = this.form.querySelectorAll(`input[name="${field.name}"]`);
                for (const radio of radioGroup) {
                    if (radio.checked) return radio.value;
                }
                return null;
            case 'file':
                return field.files;
            default:
                return field.value;
        }
    }
    
    isEmpty(value) {
        return value === null || value === undefined || 
               (typeof value === 'string' && value.trim() === '') ||
               (Array.isArray(value) && value.length === 0);
    }
    
    debounce(func, wait) {
        let timeout;
        return (...args) => {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }
    
    // Public API
    goToStep(stepIndex) {
        this.showStep(stepIndex);
    }
    
    getCurrentStepData() {
        return this.steps[this.currentStep];
    }
    
    getFormProgress() {
        return {
            currentStep: this.currentStep,
            totalSteps: this.steps.length,
            completedSteps: this.steps.filter(step => step.isCompleted).length,
            progressPercentage: ((this.currentStep + 1) / this.steps.length) * 100
        };
    }
}

// Initialize multi-step forms
document.addEventListener('DOMContentLoaded', () => {
    const multiStepForms = document.querySelectorAll('.multi-step-form');
    
    multiStepForms.forEach(form => {
        new MultiStepFormValidator(form, {
            saveProgress: true,
            validateStepOnNext: true,
            progressIndicator: true
        });
    });
});

Accessibility and User Experience

Comprehensive Accessibility Implementation

Ensuring form validation systems work for all users:

/* form-validation-styles.css - Accessible form validation styles */

/* Base form styles */
.markdown-form {
    max-width: 800px;
    margin: 0 auto;
    padding: 2rem;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    line-height: 1.6;
}

.form-group {
    margin-bottom: 1.5rem;
    position: relative;
}

.form-control {
    width: 100%;
    padding: 0.75rem 1rem;
    border: 2px solid #d1d5db;
    border-radius: 6px;
    font-size: 1rem;
    line-height: 1.5;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    background-color: #fff;
}

.form-control:focus {
    outline: none;
    border-color: #3b82f6;
    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

/* Validation states */
.form-control.validation-error {
    border-color: #dc2626;
    background-color: #fef2f2;
}

.form-control.validation-success {
    border-color: #059669;
    background-color: #f0fdf4;
}

/* Error and success messages */
.field-error {
    margin-top: 0.5rem;
    padding: 0.5rem;
    background-color: #fef2f2;
    border: 1px solid #fecaca;
    border-radius: 4px;
    border-left: 4px solid #dc2626;
}

.error-message {
    display: block;
    color: #dc2626;
    font-size: 0.875rem;
    font-weight: 500;
}

.field-warning {
    margin-top: 0.5rem;
    padding: 0.5rem;
    background-color: #fffbeb;
    border: 1px solid #fed7aa;
    border-radius: 4px;
    border-left: 4px solid #f59e0b;
}

.warning-message {
    display: block;
    color: #d97706;
    font-size: 0.875rem;
}

/* Labels and help text */
label {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 600;
    color: #374151;
}

.form-help {
    margin-top: 0.25rem;
    font-size: 0.875rem;
    color: #6b7280;
}

/* Button styles */
.btn {
    display: inline-block;
    padding: 0.75rem 1.5rem;
    margin-right: 0.5rem;
    border: 2px solid transparent;
    border-radius: 6px;
    font-size: 1rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: all 0.15s ease;
}

.btn-primary {
    background-color: #3b82f6;
    color: white;
}

.btn-primary:hover:not(:disabled) {
    background-color: #2563eb;
    transform: translateY(-1px);
}

.btn-secondary {
    background-color: #6b7280;
    color: white;
}

.btn-success {
    background-color: #059669;
    color: white;
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn:focus {
    outline: none;
    box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}

/* Multi-step form progress */
.form-progress {
    margin-bottom: 2rem;
}

.progress-bar {
    width: 100%;
    height: 8px;
    background-color: #e5e7eb;
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 1rem;
}

.progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #3b82f6, #1d4ed8);
    transition: width 0.3s ease;
    border-radius: 4px;
}

.step-indicators {
    display: flex;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 1rem;
}

.step-indicator {
    flex: 1;
    min-width: 120px;
    text-align: center;
    padding: 0.75rem;
    border: 2px solid #e5e7eb;
    border-radius: 8px;
    transition: all 0.2s ease;
}

.step-indicator.active {
    border-color: #3b82f6;
    background-color: #eff6ff;
}

.step-indicator.completed {
    border-color: #059669;
    background-color: #ecfdf5;
}

.step-number {
    display: inline-block;
    width: 32px;
    height: 32px;
    line-height: 28px;
    border-radius: 50%;
    background-color: #e5e7eb;
    color: #374151;
    font-weight: 700;
    margin-bottom: 0.5rem;
}

.step-indicator.active .step-number {
    background-color: #3b82f6;
    color: white;
}

.step-indicator.completed .step-number {
    background-color: #059669;
    color: white;
}

.step-title {
    font-size: 0.875rem;
    font-weight: 600;
    color: #374151;
}

/* Content analysis display */
.content-analysis {
    margin-top: 1rem;
    padding: 1rem;
    border: 1px solid #e5e7eb;
    border-radius: 6px;
    background-color: #f9fafb;
}

.analysis-summary {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1rem;
}

.score-indicator {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0.75rem;
    border-radius: 8px;
    min-width: 80px;
}

.score-indicator.excellent {
    background-color: #dcfce7;
    color: #166534;
}

.score-indicator.good {
    background-color: #dbeafe;
    color: #1e40af;
}

.score-indicator.fair {
    background-color: #fef3c7;
    color: #a16207;
}

.score-indicator.needs-improvement {
    background-color: #fee2e2;
    color: #991b1b;
}

.score {
    font-size: 1.5rem;
    font-weight: 700;
}

.metrics {
    display: flex;
    gap: 1rem;
    flex: 1;
}

.metric {
    text-align: center;
}

.metric .value {
    display: block;
    font-size: 1.25rem;
    font-weight: 700;
    color: #374151;
}

.metric .label {
    font-size: 0.75rem;
    color: #6b7280;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Issues and suggestions */
.issues,
.suggestions {
    margin-top: 1rem;
}

.issues h4,
.suggestions h4 {
    margin: 0 0 0.5rem 0;
    font-size: 0.875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.issues ul,
.suggestions ul {
    margin: 0;
    padding-left: 1.5rem;
    list-style: none;
}

.issue,
.suggestion {
    margin-bottom: 0.5rem;
    font-size: 0.875rem;
    position: relative;
}

.issue::before {
    content: "⚠️";
    position: absolute;
    left: -1.5rem;
}

.issue.high {
    color: #dc2626;
}

.issue.medium {
    color: #d97706;
}

.suggestion::before {
    content: "💡";
    position: absolute;
    left: -1.5rem;
}

/* Checkbox and radio styling */
.checkbox-group {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.checkbox-label {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    cursor: pointer;
    font-weight: 400;
    line-height: 1.5;
}

.checkbox-label input[type="checkbox"],
.checkbox-label input[type="radio"] {
    width: 18px;
    height: 18px;
    margin: 0;
    cursor: pointer;
}

/* Responsive design */
@media (max-width: 768px) {
    .markdown-form {
        padding: 1rem;
    }
    
    .step-indicators {
        flex-direction: column;
    }
    
    .step-indicator {
        min-width: auto;
    }
    
    .analysis-summary {
        flex-direction: column;
        align-items: stretch;
    }
    
    .metrics {
        justify-content: space-around;
    }
    
    .btn {
        width: 100%;
        margin-bottom: 0.5rem;
        margin-right: 0;
    }
}

/* High contrast mode support */
@media (prefers-contrast: high) {
    .form-control {
        border-width: 3px;
    }
    
    .form-control:focus {
        border-color: #000;
        box-shadow: 0 0 0 3px #000;
    }
    
    .validation-error {
        border-color: #d00;
        background-color: #fee;
    }
    
    .validation-success {
        border-color: #0a0;
        background-color: #efe;
    }
}

/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
    .form-control,
    .btn,
    .step-indicator,
    .progress-fill {
        transition: none;
    }
    
    .btn:hover:not(:disabled) {
        transform: none;
    }
}

/* Print styles */
@media print {
    .btn,
    .step-navigation,
    .content-analysis {
        display: none;
    }
    
    .form-control {
        border: 1px solid #000;
        background: transparent;
    }
    
    .validation-error,
    .validation-success {
        border: 2px solid #000;
    }
}

/* Focus indicators for keyboard navigation */
.form-control:focus,
.btn:focus,
.checkbox-label input:focus + .checkmark,
.step-indicator:focus {
    outline: 3px solid #3b82f6;
    outline-offset: 2px;
}

/* Screen reader only content */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Animation for validation feedback */
@keyframes shake {
    0%, 100% { transform: translateX(0); }
    10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
    20%, 40%, 60%, 80% { transform: translateX(5px); }
}

.validation-error.shake {
    animation: shake 0.5s ease-in-out;
}

/* Loading states */
.btn.loading {
    position: relative;
    color: transparent;
}

.btn.loading::after {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -8px;
    margin-left: -8px;
    width: 16px;
    height: 16px;
    border: 2px solid transparent;
    border-top: 2px solid currentColor;
    border-radius: 50%;
    animation: spin 1s linear infinite;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

Conclusion

Advanced Markdown form validation and input handling systems provide the foundation for creating interactive, user-friendly documentation platforms that maintain data quality while delivering exceptional user experiences. By implementing comprehensive validation frameworks, real-time content analysis, and accessible form interfaces, technical teams can create documentation systems that not only inform but also effectively collect and validate user input across diverse use cases and user needs.

The key to successful form validation implementation lies in balancing thorough validation with user experience, ensuring that validation systems guide users toward success rather than creating barriers to completion. Whether you’re building simple feedback forms or complex multi-step content submission workflows, the validation techniques and accessibility considerations covered in this guide provide the foundation for creating robust, inclusive, and professional form experiences.

Remember to implement progressive enhancement strategies that work without JavaScript, provide clear and actionable error messages, and continuously test your forms with real users across different devices and assistive technologies. With proper implementation of advanced form validation and input handling, your Markdown documentation can achieve the same level of interactivity and data quality that users expect from modern web applications while maintaining the simplicity and accessibility that makes Markdown such a powerful format for technical communication.