Clean And Accessible Form Foundation

As soon as you drop tables you find that making nicely formated and accessible forms is not that simple. There are many discussed methods to achieve this and there will always be something to argue about them. Having said that I present you here with a solution that in most of the cases works for me. I hope you find this useful.

Final product: View the demo Download


There were a couple of things I had in mind when creating this form, first of all the code would have to be valid XHTML, clean semantic and well formated. This would need to have a good balance between accessibility and flexibility to make it portable and easy to style. This way you have more chances to easily copy and modify to adjust to different needs.

The Markup:

Beyond the input elements XHTML gives us a set of tags to build our forms in an accessible way. I like to use Fieldsets, Legends and Labels. To display nicely aligned radio and checkbox buttons I use classes in the fieldsets: .checkbox and .radio. If the form requires multiple colomun-aligned checkboxes or radio buttons I use the class .multiple. To style the overall form correctly I use the class .cleanform.

<form class="cleanform" action="#">
		<legend>Personal Details:</legend>
		<label for="name" >Name <span class="required">(required)</span></label>
		<input name="name" id="name" type="text" value="Example text." />
		<label for="email">Email <span class="required">(required)</span></label>
		<input name="email" id="email" type="text" value="Example text." />
		<label for="inquiry">Inquiry</label>
		<select name="inquiry" id="inquiry">
		<option value="comment">Comment</option>
		<option value="suggestion">Suggestion</option>
		<option value="feedback">Feedback</option>
		<label for="comments">Comments</label>
		<textarea name="comments" id="comments" rows="10" cols="50">Example text.</textarea>
	<fieldset class="radio">
		<legend>Subscribe to my Newsletter? <span class="required">(required)</span></legend>
		<label><input type="radio" name="newsletter" value="Yes" /> Yes</label>
		<label><input type="radio" name="newsletter" value="No" /> No</label>
	<fieldset class="checkbox">
		<legend>Aditional information</legend>
		<label><input type="checkbox" name="foo" value="Foo yes" /> Foo</label>
		<label><input type="checkbox" name="bar" value="Bar yes" /> Bar</label>
	<fieldset class="checkbox multiple">
		<legend>Multiple Checkboxes</legend>
		<label><input type="checkbox" name="foo2" value="Foo yes" /> Foo</label>
		<label><input type="checkbox" name="bar2" value="Bar yes" /> Bar</label>
		<label><input type="checkbox" name="foo3" value="Foo yes" /> Other</label>
		<label><input type="checkbox" name="bar3" value="Bar yes" /> Example</label>
		<label><input type="checkbox" name="foo4" value="Foo yes" /> Multiple</label>
		<label><input type="checkbox" name="bar4" value="Bar yes" /> Checkboxes</label>
		<label><input type="checkbox" name="foo5" value="Foo yes" /> More</label>
		<label><input type="checkbox" name="bar5" value="Bar yes" /> Select</label>
	<p><button type="submit">Submit Form</button></p>

As you may see its a very simple and clean markup, I group related form elements in fieldsets and make use of the legend and label elements.

I also have the required labels. A common practice for this is to add an asterisk in red, I am not against that but I prefer to use the word “required” when possible. To achieve this I use the span element with a class named .required.

Optionally I add a little intro to make the form more intuitive:

<div class="formInfo">
	<h2>Contact me Form</h2>
	<p>Please complete the following form to reach me. Thank you!</p>


CSS code for the cleanform class and its elements:

/* General */
.cleanform {
	margin:1em auto
/* Elements */
.cleanform  label,.cleanform legend{
	margin:0.3em 0
.cleanform fieldset{
	border:1px solid #ddd;
	margin:0 0 0.5em 0
.cleanform label {
.cleanform fieldset input {
.cleanform .radio input,
.cleanform .checkbox input {
	margin:0 1.5em 0 0
.cleanform input, .cleanform textarea, .cleanform select {
	border:1px solid #bbb;
.cleanform .radio label, .cleanform .radio input,
.cleanform .checkbox label, .cleanform .checkbox input {
	margin:0 1.5em 0 0
.cleanform .radio input, .cleanform .checkbox input {
	margin:0 0.3em 0 0
.cleanform .multiple label{
.cleanform .multiple input {
/* Button */
.cleanform button {
	margin:0.3em 0;
	border:1px solid #ccc;
.cleanform button:hover {
	border:1px solid #c6d880;
.cleanform button:active {
	border:1px solid #000
/* information */
.cleanform .formInfo {
	border-bottom:0.1em solid #ddd
.cleanform .formInfo h2 {
.cleanform .formInfo p{
.cleanform .required {

With the styles above you have a clean, accessible and valid foundation from where you can style the form accordingly to your project needs.

Final product: View the demo Download


I hope you found it useful and of course I suggest you to always choose the method/solution that you feel most comfortable with. Critics and comments are welcome, thanks!

This method has been tested in: IE6, IE7, Firefox 3 ( Mac & PC ), Google Chrome, Opera ( Win ) and Safari 3.1.

Reactions (37)

  1. I would suggest putting the input within the label for the radio buttons and checkboxes


    its kind of an accessibility feature

  2. Hey great write up! I would consider putting radio button and checkbox labels on the right side of the input element. This the more usable convention.

  3. looks great. but why not using ‘s for label/input combinations? that looks great even without css.

  4. Hi guys, thanks for the comment and heads up. My mistake just updated the post and file. Thanks again :)

  5. I’ve noticed more and more lately on my personal projects that I have been wrapping each label + form control pair in a div:

    <div class="form-field">
    <label>...<br />
    <input />

    And I also do the same thing with the submit button:

    <div class="form-submit">
    <input />

    It just seems to give me a little more control over how I do things. It also helps establish a generic pattern that I can use across most sites.

  6. Hi Dustin, yes thats an option, would say mostly if you need to do a more advanced form style. Anyways, thanks for the addition!

  7. Somewhere on the internet I recently saw label element that wraps around the input. It makes a little sense to have the label and form element are grouped together.

    Some Label

    This might be an alternative for dustin’s wrapping a div around everything. You could use the label element for positioning and spacing. You could then apply some styles to the input to display inline with the label or below and then adjust spacing with margins.

  8. This is a really good article for me. I’m a good programmer but a generally terrible web developer. It’s nice to see the standards based CSS stuff presented in a clean way. Forms have been a chronic pain in my side. I will try this approach.

    I also appreciated the education value of the other commentors. Thanks, everyone.

  9. There is a lot of times where I will make the form be something of
    legend /legend

    anything for more options in the end, better to plan ahead then to have to go back through, and for some reason I just really like list items

  10. Pingback :: Web Development

  11. I second what Darin said, thanks for the info about the forms [been struggling with this for a while] and also the user comments.

  12. David Hucklesby

    Nice design that works well cross-browser – not an easy thing to achieve. Thank you.

    @Dustin, @Evan:
    (quote)wrapping the input with the label can have serious consequences!(/quote)

    See this article:

  13. Very nice article Matt! I’m also very happy to see that you keep your HTML nice and clean. most forms have absolutely no need for extra containing elements :)

    As I said, thanks to this article I’m going to add required stylings to my css framework :)

  14. Pingback Clean Accessible Form Foundation | Castup

  15. hm, i just noticed that my comment is broken.
    i meant:

  16. @Dustin
    I don’t put my inputs in the label tags but I do agree with you that putting your label/input combinations within div tags gives you more control and makes it easier.

  17. Pingback Enlaces semanales que no he publicado (1) | Cosas sencillas

  18. @David Hucklesby – Good call on wrapping the inputs with the label. I’d like to do a little more testing on that.

  19. Pingback Clean Accessible Form Foundation | Castup

  20. Nicely done, but I think that you make a mistake in overriding the default style of the submit button. I know its prettier the way you made it, but it is harder to see, and it isn’t obvious that its a button. If you replace a button with something, it has to still look like a button.

    • Hi Jon, thanks for the comment. I have to say its the first time I hear this type of button is hard to recognise, it’s interesting to see that this happened to you cause it then probably happens to other people too, thanks for the suggestion.

  21. Pingback » Blog Archive » links for 2009-01-12

  22. Great writeup and CSS demo again , Matt. Great to see the cross browser compatibility. Keep em’ coming.

    • Thanks Naser, glad you found it useful, im sure there will be more coming soon :)

  23. Green Wev Developer

    Thank you for this awesome foundation. I’m just starting to learn how to build forms, so forgive my naivety, but in order for this form to actually function and send information I would need to use some kind of script (cgi script), correct? I realize there are other ways (php, asp, etc), but what would be simplest route for one just learning?


    • Hi Green, glad you found it useful. I would encourage you to use PHP to handle your forms, as thats what i feel im more comfortable with. If you want a good start point you could check a contact form script i did some time ago.

  24. Hey, thanks for your cool style. I was just going to search on delicious for a nice css form library for my current web project and then saw this page at the front page. You probably will see it on my homepage in a few months when I relaunch it. (:

    • Hi Ch0wn, Thanks for the nice comment. Best of the lucks with your website re-launch!

  25. Thanks for sharing this clean form I really like it

  26. Hello Matt,

    I’ve looked through all your contact form scripts etc and like to say there great but i’ve got a small problem which i’ve been looking for a solution for a long time.

    I’m no where near a great programmer a novice but i hate the idea of my client’s customer going to a php page i’d like thenm to stay on the same page to fill in the contact form but i understand that i cannot add php content into .html page so i’m looking for a way where the form process in the background in php but allows the visitor to fill in the form through existing contact.html page.

    Can you suggest a way of making this possible without changing my .html page into a php page?

    Thanks in advance!

    • Hi Kiran, thanks for the nice comment! as for you question, yes there is a solution, you could request the php via ajax. There’s a lot of good tutorials out there on how to do it. Or you could even user a jQuery plugin which might be simpler.

  27. Pingback Clean Accessible Form Foundation « developer news

  28. can you make a modification to create columns for radio and checkboxes. With your current implementation, when you have a lot of choices , they just flow down and makes it hard to read

    • @Jose post updated, now radio buttons and checkboxes can be column aligned with the .multiple class.

  29. Thank you. That works. Now for a question. Many form css templates change the way the submit button looks. BUT, what if I want the standard way? I commented all the button section on the css, but still the button looks flat(not the normal way). I think, correct me if I am wrong, that is taking the properties of other element because of lines like this
    .cleanform input,

    Can the css be made in such a way that the properties of the element in the form does not affect the look of the submit button?

    Thank you

    • @jose if you are using the button element ( as in this example ) instead of an input with the type submit, then commenting the button css section should return your element to it’s default style. Now, in both the online demo and the download I applied a quick reset to all elements * { margin:0; padding: 0 } , This is probably causing you to see the button look “flat”. Try removing or commenting that part of the code to see if it helps. Thanks for the comments!