Fawyd
Fawyd

Reputation: 1435

Styling form error message - bootstrap/rails

The error messages for my rails form look terrible with bootstrap. Does anyone know a solution for better (nice looking) error messages? I use Rails and Bootstrap.

My form (it's a helper) is like this:

<%= form_for(@user) do |f| %>
  <% if @user.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>

      <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="form-inline">
    <%= f.text_field :email, class:'input-large', placeholder:'Test' %>
<!--   </div>
  <div class="actions"> -->
    <%= f.submit class:'btn btn-large btn-success' %>
  </div>
<% end %>

The error message

Upvotes: 22

Views: 30389

Answers (8)

Georges Atalla
Georges Atalla

Reputation: 41

I've create a custom initializer to have each field having its own errors below it

# app/config/initializers/bootstrap_form_errors_customizer.rb

ActionView::Base.field_error_proc = proc do |html_tag, instance|
  is_label_tag = html_tag =~ /^<label/
  class_attr_index = html_tag.index 'class="' 

  def format_error_message_to_html_list(error_msg)
    html_list_errors = "<ul></ul>"
    if error_msg.is_a?(Array)
      error_msg.each do |msg|
        html_list_errors.insert(-6,"<li>#{msg}</li>")
      end
    else 
      html_list_errors.insert(-6,"<li>#{msg}</li>")
    end
    html_list_errors
  end

  invalid_div =
    "<div class='invalid-feedback'>#{format_error_message_to_html_list(instance.error_message)}</div>"

  
  if class_attr_index && !is_label_tag
    html_tag.insert(class_attr_index + 7, 'is-invalid ')
    html_tag + invalid_div.html_safe
  elsif !class_attr_index && !is_label_tag
    html_tag.insert(html_tag.index('>'), ' class="is-invalid"')
    html_tag + invalid_div.html_safe
  else
    html_tag.html_safe
  end
end

Upvotes: 0

medBouzid
medBouzid

Reputation: 8442

Another variation with SCSS only

#error_explanation{
  background: #f23551;
  color: #fff;
  border-radius: 4px;
  margin-bottom: 20px;
  h2{
    padding: 20px;
    margin: 0;
    font-size: 20px;
  }
  ul{
    background: #fff;
    color: #e5324a;
    border: 1px solid #F23551;
    margin: 0;
    list-style: none;
    padding: 14px 0;
    li{
      padding: 4px 20px;
      &:before {
        content: '×';
        font-weight: bold;
        font-size: 20px;
        margin-right: 10px;
      }
    }
  }
}

Upvotes: 0

Rajkaran Mishra
Rajkaran Mishra

Reputation: 4952

I have implemented Rabbott's view helper in Rails 5 and Bootstrap 4:

def errors_for(object)
    if object.errors.any?
      content_tag(:div, class: 'card text-white bg-danger mb-3') do
        concat(content_tag(:div, class: 'card-header') do
          concat(content_tag(:h4) do
            concat "#{pluralize(object.errors.count, 'error')} prohibited this #{object.class.name.downcase} from being saved:"
          end)
        end)
        concat(content_tag(:div, class: 'card-body') do
          concat(content_tag(:ul) do
            object.errors.full_messages.each do |msg|
              concat content_tag(:li, msg)
            end
          end)
        end)
      end
    end
  end

And it looks like this: enter image description here

Upvotes: 4

Dieglock
Dieglock

Reputation: 169

Maybe a simpler one is search for ids and classes on the form itself. Works for any combo.

By default, this are the lines included in scaffold to arrange the error messages. You can do with them whatever you want. Just have to extend them in your css.scss file:

.field_with_errors {
  padding: 2px;
  background-color: red;
  display: table;
}

#error_explanation {
  width: 450px;
  border: 2px solid red;
  padding: 7px 7px 0;
  margin-bottom: 20px;
  background-color: #f0f0f0;
}

#error_explanation h2 {
  text-align: left;
  font-weight: bold;
  padding: 5px 5px 5px 15px;
  font-size: 12px;
  margin: -7px -7px 0;
  background-color: #c00;
  color: #fff;
}

#error_explanation ul li {
  font-size: 12px;
  list-style: square;
}

In case something is not working, check the navigator in developer mode. There you should be able to find all the html and css rails is creating...

Upvotes: 0

Rabbott
Rabbott

Reputation: 4332

A little late I realize, but I just ran into this today with Rails 4 and Bootstrap 3, I ended up making a view helper to display errors using a panel:

Rails 4 / Bootstrap 3

def errors_for(object)
    if object.errors.any?
        content_tag(:div, class: "panel panel-danger") do
            concat(content_tag(:div, class: "panel-heading") do
                concat(content_tag(:h4, class: "panel-title") do
                    concat "#{pluralize(object.errors.count, "error")} prohibited this #{object.class.name.downcase} from being saved:"
                end)
            end)
            concat(content_tag(:div, class: "panel-body") do
                concat(content_tag(:ul) do
                    object.errors.full_messages.each do |msg|
                        concat content_tag(:li, msg)
                    end
                end)
            end)
        end
    end
end

enter image description here

Rails 4 / Bootstrap 4 Beta

def errors_for(object)
    if object.errors.any?
        content_tag(:div, class: "card border-danger") do
            concat(content_tag(:div, class: "card-header bg-danger text-white") do
                concat "#{pluralize(object.errors.count, "error")} prohibited this #{object.class.name.downcase} from being saved:"
            end)
            concat(content_tag(:div, class: "card-body") do
                concat(content_tag(:ul, class: 'mb-0') do
                    object.errors.full_messages.each do |msg|
                        concat content_tag(:li, msg)
                    end
                end)
            end)
        end
    end
end

enter image description here

Rails 4 / Bootstrap 4 Beta List Group Variation

def errors_for(object)
    if object.errors.any?
        content_tag(:div, class: "card border-danger") do
            concat(content_tag(:div, class: "card-header bg-danger text-white") do
                concat "#{pluralize(object.errors.count, "error")} prohibited this #{object.class.name.downcase} from being saved:"
            end)
            concat(content_tag(:ul, class: 'mb-0 list-group list-group-flush') do
                object.errors.full_messages.each do |msg|
                    concat content_tag(:li, msg, class: 'list-group-item')
                end
            end)
        end
    end
end

enter image description here

I dropped it in application_helper and call it in my form views

<%= errors_for(@user) %>

Maybe someone will stumble upon this and find it useful.

Upvotes: 15

Chloe
Chloe

Reputation: 26294

Bootstrap 4 Alpha 6

I copied the compiled Bootstrap CSS from

https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css

Searched for .has-danger, copied all the classes, did a search & replace on .has-danger for .field_with_errors, and I also added .field_with_errors label

.field_with_errors label,
.field_with_errors .form-control-feedback,
.field_with_errors .form-control-label,
.field_with_errors .col-form-label,
.field_with_errors .form-check-label,
.field_with_errors .custom-control {
  color: #d9534f;
}

.field_with_errors .form-control {
  border-color: #d9534f;
}

.field_with_errors .input-group-addon {
  color: #d9534f;
  border-color: #d9534f;
  background-color: #fdf7f7;
}

.field_with_errors .form-control-danger {
  background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23d9534f' viewBox='-2 -2 7 7'%3E%3Cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3E%3Ccircle r='.5'/%3E%3Ccircle cx='3' r='.5'/%3E%3Ccircle cy='3' r='.5'/%3E%3Ccircle cx='3' cy='3' r='.5'/%3E%3C/svg%3E");
}

I wasn't able to get the input groups addons to display correctly, as it wraps the input with a <div>.

bootstrap 4 with rails errors

Docs: https://v4-alpha.getbootstrap.com/components/forms/#validation

Honestly some of these classes are not used because Rails doesn't have an obvious way to set classes on error fields.

For the error list, I just used this simple class

#error_explanation {
  color: red;
}

Upvotes: 3

crispychicken
crispychicken

Reputation: 2662

Take a look at how Michael Hartl does it in railstutorial. screenshot

And thats the used css:

#error_explanation {
  color: #f00;
  ul {
    list-style: none;
    margin: 0 0 18px 0;
  }
}

.field_with_errors {
  @extend .control-group;
  @extend .error;
 }

He describes everything here.

If you also want the little star at the beginning of every line you have to include it in your form:

     <div id="error_explanation">
        <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
        <ul>
          <% @user.errors.full_messages.each do |msg| %>
            <li> * <%= msg %></li>    <--- insert here
          <% end %>
        </ul>
     </div>
      ...

Upvotes: 25

Jay Killeen
Jay Killeen

Reputation: 2922

Just in case someone stumbles here and is using Bootstrap 4 alpha with rails 5 and bootstrap_form_for gem. I use:

<div class="form-group">
  <%= f.alert_message "Please fix the errors below." %>
</div>

which looks really nice.

enter image description here

Upvotes: 5

Related Questions