How to Customize Rails Form Error Handling.
By default, when Rails detects validation errors on a form field, it wraps the form element in a <div class="field_with_errors">
(coming from ActiveModelInstanceTag).
<!-- erb -->
<%= form.label :name %>
<%= form.text_field :name %>
<!-- html -->
<label for="name">Name</label>
<input type="text" name="name" id="name">
<!-- html with error -->
<div class="field_with_errors">
<label for="name">Name</label>
</div>
<div class="field_with_errors">
<input type="text" name="name" id="name">
</div>
This behavior is intended to make it easier to style invalid fields. For example, you can add CSS like this to highlight error states:
.field_with_errors input,
.field_with_errors textarea,
.field_with_errors select {
border: 2px solid red;
background-color: #ffe6e6;
}
While this works well in theory, the extra wrapper often introduces issues:
- It can disrupt CSS layouts, especially in grid or flexbox designs.
- It adds unwanted HTML, making your markup harder to debug.
- It can interfere with JavaScript selectors that expect specific input fields.
This additional wrapper can cause more harm than good. And more importantly maybe you prefer to write your own components to highlight form validation errors as it allows you to style the field- and label-inputs exactly how you want.
Thankfully, there are ways to handle it gracefully.
Solution 1: Disable the Wrapper Entirely
The simplest solution is to disable the .field_with_errors wrapper entirely so that Rails outputs the form field as-is, without wrapping it in additional HTML.
Create an initializer file named config/initializers/field_with_errors.rb
:
ActionView::Base.field_error_proc = proc do |html_tag, instance|
html_tag.html_safe
end
This approach ensures that Rails outputs the form field without any additional HTML. It’s clean, simple, and avoids layout issues.
However, this method doesn’t provide a way to visually highlight fields with errors. If you still want to style invalid fields, consider the next solution.
Solution 2: Add an Error Class Dynamically
For more control over styling, you can append an error class (e.g., is-invalid
) directly to the form field when an error occurs. This keeps your HTML clean and ensures invalid fields are visually distinguishable.
Use this initializer instead:
ActionView::Base.field_error_proc = proc do |html_tag, instance|
error_class = "is-invalid"
element = Nokogiri::HTML::DocumentFragment.parse(html_tag)
node = element.children.first
if node
node["class"] = class_names(
node["class"],
error_class
)
end
element.to_s.html_safe
end
This approach uses Nokogiri
to parse the HTML, dynamically appends the is-invalid
class to the field, and ensures the output is clean without wrapping it in a div
.
This method retains the ability to style fields with errors while avoiding the layout-breaking wrapper.
CSS Workaround: Embrace the Wrapper
If you'd rather not change Rails's default behavior, you can adapt your CSS to work with .field_with_errors
.
Using display: contents;
makes the .field_with_errors
wrapper effectively invisible in the layout. It removes the wrapper's box model while keeping its children intact, ensuring your layout stays consistent without altering the HTML structure.
.field_with_errors {
display: contents;
}
.field_with_errors input,
.field_with_errors textarea,
.field_with_errors select {
border: 2px solid red;
background-color: #ffe6e6;
}
This CSS ensures that the wrapper doesn't interfere with your layout while still highlighting invalid fields.
Global Impact of field_error_proc
Customizing ActionView::Base.field_error_proc
affects all Rails form builders globally. This means any gem or library that relies on Rails form helpers will also inherit your customizations. While this can be convenient for uniform styling, it could lead to unintended side effects.
To limit the impact, you can wrap your form field logic in a helper method or a custom builder that applies the same customization but only within the scope of your own forms.
Security Note: Beware of XSS Vulnerabilities
When customizing form error handling, always consider the potential for XSS
(Cross-Site Scripting) vulnerabilities. Rails escapes output by default when using form helpers like text_fiel
, text_area
... so yo're usually safe. However, if your customization involves manually inserting error messages or modifying user-generated content in the HTML, ensure that all content is properly escaped.
You can use the html_safe
method only for strings you know are safe, and prefe h()
or ERB::Util.html_escape
to escape potentially dangerous content.
Conclusion
Depending on your needs, you now have three approaches to handle Rails's .field_with_errors
behavior:
- Disable the wrapper entirely for clean, minimal HTML.
- Add an error class dynamically for fine-grained control over styling.
- Style the wrapper with CSS to embrace the default behavior without layout issues.
Choose the solution that best fits your project,
and take back control of your forms ✊