Easier form styling in Rails

Update:

The information in this article has been superseded by FormClassifier. Read this for background, but follow that link to download updated code.

Web forms are always problematic to style. Even once you get them to the point where they look acceptable across all your supported browsers, you inevitably remember that you need a file upload control, which can’t be styled at all, leaving you to decide between going with the browser defaults or creating a custom control in Flash.

I can’t solve the file upload control problem for you, I’m afraid, but I can help you get around another common annoyance with form styling: The fact that text inputs and submit buttons are both input elements and therefore styles written for one will also be applied to the other, which is rarely what you want.

In a perfect world we could reliably use CSS 2.1 attribute selectors to target input elements with the type attribute set to “text” or “submit” but, alas, any world where people are still using Internet Explorer 6 is far from perfect. CSS3 selectors would be nice but even these 2.1 selectors would solve this problem for us.

Most people address this by setting a class attribute similar to “button” or “textfield” as appropriate on the form elements they want to style. This works great except that it’s tedious and error-prone. I use this method myself and am always having to go back and add these classes when I realize I forgot them the first time around.

When I recently had a similar problem on a Ruby on Rails application I’m working on I came up with a better answer: Ruby allows for method overriding and this can be used to our advantage when using the Rails ActionView form helpers. Simply override the form tag helpers with your own that adds the appropriate “button” or “textfield” classes automatically. Here’s an example:

Normally, the text_field_tag method works like this. The first line is the code you use in your view, and the second is what the form helper generates for you:

<%= text_field_tag "name" %>
<input id="name" name="name" type="text" />

Now, you could use :class => "textfield" here but that’s no different from including a “textfield” class in your HTML, and is best avoided for the reasons touched on above.

For the project I’m working on, I wrote new form helpers that override certain Rails methods in order to do this for me automatically. I put these new methods in a new module at app/helpers/form_helper.rb. As an example, here’s the code I use to insert a “textfield” class to all my text fields:

module FormHelper
 
	# Override text_field_tag method in order to add a default class
	def text_field_tag(*args)
		# Check options hash
		args = check_options_hash(args)
		# Append class name to string
		args.last[:class] += 'textfield'
		super(*args)
	end
 
	# Used by overridden form helpers above
	def check_options_hash(args)
		# Make sure an options hash exists
		unless args.last.kind_of?(Hash)  
			args << {}  
		end
		# Make sure :class key exists in hash, append space if it does
		if args.last.include?(:class)
			args.last[:class] += ' '
		else
			args.last[:class] = ''
		end
		return args
	end
 
end

Once this code is in place, make it accessible to all your views by adding this line to app/helpers/application_helper.rb:

include FormHelper

In a nutshell, what this does is overrides the default text_field_tag method with my own version that adds the appropriate class to the HTML options hash, then passes the supplied arguments, along with my own addition, to the original Rails text_field_tag method. I split out check_options_hash into its own method because I need to use it in each form helper I override and this helps keep things DRY.

So, using the example above, my text fields now come out looking like this:

<%= text_field_tag "name" %>
<input class="textfield" id="name" name="name" type="text" />

I can now write CSS to style input.textfield and input.button knowing that these classes will always be present on these elements, making forms easier to style and reducing time chasing down missing class attributes.

Update:

The information in this article has been superseded by FormClassifier. Read this for background, but follow that link to download updated code.

Your comments are welcome

Comment notes

  • Fields marked with a * are required.
  • Your e-mail address will not be published or spammed.
  • Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="">

About Me

Kenn Wilson is a Linux system administrator and web technologist in Oakland, California who spends an inordinate amount of his free time researching and keeping up on the latest web trends and technologies.