How to Customize Rails Form Error Handling.

Published on December 11, 2024
Written by Victor Cobos

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:

  1. Disable the wrapper entirely for clean, minimal HTML.
  2. Add an error class dynamically for fine-grained control over styling.
  3. 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 ✊

Subscribe to get future articles via the RSS feed .