Home » Html » Can form styling be done without tables?

Can form styling be done without tables?

Posted by: admin November 30, 2017 Leave a comment


I’ve gotten used to using <table>s for aligning my form fields perfectly. This is how I commonly write my forms:

<table border="0">
     <td><label for="f_name">First name:</label></td>
     <td><input type='text' id='f_name' name='f_name' /></td>
     <td class='error'><?=form_error('f_name');?></td>

I know this is bad practice, and I want to use css, <label>s, <div>s, or a cleaner method. However, the fact is, <table>s work extremely well for the forms. Everything is aligned exactly right, the spacing is perfect, all errors exactly below each other, etc.

I recently tried using <dt> and <dd> tags for a form, but I ended up reverting back to tables just because they looked so much better.

Is there any hope for people like me, or are tables just the best way to create forms?


This might not get a lot of support but here’s my two cents:

In some situations tables are easier for layout; such as three columns or forms (albeit there are some great suggestions here for doing a pure css form layout so don’t ignore those either.)

Processes and methodologies can make good servants but are poor masters.
   - Mark Dowd, John McDonald & Justin Schuh 
     in "The Art of Software Security Assessment"

I believe that this quote very strongly applies to this situation. If your table layout is working for you, not causing accessibility issues and isn’t broken – then don’t fix it.

Phrases like: “you should”, “must”, “always” – make me scared, because one-size-doesn’t-fit-all! Take zealots with a grain of salt.


Yes, use labels and CSS:

<label class='FBLabel' for="FName">First Name</label>
<input value="something" name="FName" type="text" class='FBInput'>


.FBLabel, .FBInput {

See: http://www.alistapart.com/articles/prettyaccessibleforms


If you don’t use tables you need to know the width of your labels upfront. This can often be a problem for multi-language sites (i18n).

With tables, they stretch to fit labels of differing sizes. CSS alone can’t do that yet in a well-supported way.


A List Apart has a good article about this kind of thing. It’s not as simple as you’d hope but I’ve found the extra work is worth it given how much cleaner your forms will be.


Why do you not want to use tables? It sounds like they are working perfectly for you now. Are you worried about accessibility issues? Just because it is a table doesn’t mean that accessibility will suffer.

I want to caution you from creating a new solution to a solved problem for nothing other than purity’s sake. Even if you are worried about semantics, what kind of semantics describe a form anyway?


I use the following method most of the time and it allows me to get all my alignment set up exactly how I like it. As you can see, it gives me a great number of hooks for CSS and JS.

<form id="login-form" action="#" method="post">
        <label id="for-email" for="email">
            <span class="label-title">Email Address <em class="required">*</em></span>
            <input id="email" name="email" type="text" class="text-input" />

        <label id="for-password" for="password">
            <span class="label-title">Password <em class="required">*</em></span>
            <input id="password" name="password" type="password" class="text-input" />

    <ul class="form-buttons">
        <li><input type="submit" value="Log In" /></li>
</form><!-- /#login-form -->


Really depends on who you talk to. The purists say use CSS because the table element was not meant for layout. But for me, if it works, why change it? I do use CSS now for layout, but I still have plenty of legacy code I have not and will not change.


There are tons of ways out there to do it without tables. Once you get the basic format down it’s as easy to work with as tables are, it’s just the initial playing around that can be a pain. So, just look to others that have already done the work of figuring it all out for you:

I also documented the method I’ve settled on last week (a snippet):

<form action="/signup" method="post">
<legend>Basic Information</legend>
<li><label for="name">Name <span class="error">*</span>
    </label><input type="text" id="name" name="name" size="30" /></li>
<li><label for="dob">Date of Birth <span class="error">*</span></label>
    <div class="inputWrapper">
    <input type="text" id="dob" name="dob" size="10" />
    <span class="note">YYYY-MM-DD</span></div></li>
<li><label for="gender">Gender <span class="error">*</span></label>
    <select id="gender" name="gender">
    <option value=""></option>
    <option value="female">Female</option>
    <option value="male">Male</option>

And the CSS:

fieldset { 
    margin: 0 0 20px 0; } 

fieldset legend { 
    font-weight: bold; 
    font-size: 16px; 
    padding: 0 0 10px 0; 
    color: #214062; } 

fieldset label { 
    width: 170px; 
    float: left; 
    vertical-align: top; } 

fieldset ol { 
    margin: 0;
    padding: 0;} 

fieldset ol li { 
    padding-left: 0; 
    margin-left: 0; } 

fieldset ol li input, 
fieldset ol li select, 
fieldset ol li textarea { 
    margin-bottom: 5px; } 

form fieldset div.inputWrapper { 
    margin-left: 180px; } 

.note { 
    font-size: 0.9em; color: #666; }

    color: #d00; }


The answers above are all very fine and there are indeed nice ways of laying out tables using css, however it becomes very difficult when you have a form with multiple columns.

I have really struggled, and that is probably a reflection on me not the capabilities of CSS, to come up with good looking layouts for multiple column forms without resorting to tables.


There’s no one-size-fits-all for this. The table example you used can be improved on, though:

      <th scope="row"><label for="f_name">First name:</label></th>
        <input type='text' id='f_name' name='f_name' />
        <?php form_error('f_name'); ?>
    <!-- ... -->

Not too sure about the error part; I think it makes more sense putting it next to the input than having a separate column for it.


I have used this in the past fairly effectively:


    <label for="myTextBox">Name</label>
    <span class="field"><input type="text" name="myTextBox" id="myTextBox" /></span>
    <span class="error">This a message place</span>


<style type="text/css">
fieldset label, fieldset .field, fieldset .error { display: -moz-inline-box; display: inline-block; zoom: 1; vertical-align: top; }
fieldset p { margin: .5em 0; }
fieldset label { width: 10em;  text-align: right; line-height: 1.1; }
fieldset .field { width: 20em; }

The only really gotcha is Firefox 2 which gracefully degrades. (see the -moz-inline-box which is a bit of hack, but not too bad)


I had this problem too, but with the cocidil that I had a menu in the left (also with float:left in it).

So. My solution was:

<div class="new">
     <label class="newlabel">Name</label>
     <input type="text" name="myTextBox" id="myTextBox" />


.new {
.newlabel {
    min-width: 200px;
    float: left;

I think, it would work in the form class too, but in reality I had more forms in the ‘new’ class.


Most of the non-table based answers here rely on pre-determined fixed widths, which can be a pain for internationalisation, or any other scenario where you can’t be certain of the required width for labels.

But CSS has display: table for this very reason:


<div class="form-fields">
  <div class="form-field">
    <label class="form-field-label" for="firstNameInput">First Name</label>
    <div class="form-field-control"><input type="text" id="firstNameInput"></div>
    <div class="form-field-comment">Required</div>
  <div class="form-field">
    <label class="form-field-label" for="lastNameInput">Last Name</label>
    <div class="form-field-control"><input type="text" id="lastNameInput"></div>
    <div class="form-field-comment">Required</div>


.form-fields {
  display: table;

.form-field {
  display: table-row;

.form-field-comment {
  display: table-cell;
  padding: 3px 10px;