A Stimulus controller for validating html form inputs and rendering their errors in a custom error element.
yarn add stimulus-inline-input-validations
import { InputValidator } from "stimulus-inline-input-validations"
application.register("input-validator", InputValidator)
Validates min,max length of a string
Validates that a field is not blank
Validates if a field is a number
Validates email format
Validates strong password
Length, Presence, Email
Bulk validations via a json-friendly string
font-size: 14px; color: blue
font-bold text-purple-600 (Tailwind)
<form data-controller="input-validator">
...
</form>
<input type="text" data-input-validator-target="field" data-field="userName">
<div data-input-validator-target="errors" data-field="userName"></div>
<input ... data-validates-length="5,10" data-validates-numericality data-validates-email>
<div data-input-validator-target="errors" data-field="userName">
<div error="length-min">Too short. Minimum 5 characters</div>
<div error="numericality">Must be a number</div>
<div error="email">Invalid email format</div>
</div>
module ApplicationHelper
def json_validations_for(model, field)
validations_hash = {}
validators = model.class.validators_on(field)
validators.each do |validator|
validator_name = validator.class.name.demodulize.underscore.to_sym
if validator_name == :length_validator
options = validator.options.dup
validations_hash[:length] = { min: options[:minimum].present? ? options[:minimum] : 1,
max: options[:maximum].present? ? options[:maximum] : 1000 }
end
validations_hash[:presence] = true if validator_name == :presence_validator
validations_hash[:numericality] = true if validator_name == :numericality_validator
end
validations_hash[:strong_password] = true if field == :password
validations_hash[:email] = true if field == :email
validations = validations_hash.map do |key, value|
{ key.to_s => value }
end
validations.to_json.html_safe
end
end
<%= f.text_field :email,
data: {
input_validator_target:"field",
field: :email,
validations: json_validations_for(@user, :email)
}%>
<div data-input-validator-target="errors" data-field="email"></div>