7

What's the best way to use <input type="radio"> in HTML?

I'm looking for HTML that's semantically good, whose formatting is configurable via CSS.

I want to be able to style/render it to look something like:

    Car: (o) Yes
         (X) No
         (o) Maybe

  Train: (o) Yes
         (o) No
         (X) Maybe

Address: [An input text box     ]

Thinking of the CSS, I think that I'd like the labels on the left (e.g. "Car" and "Bus") to be in some kind of text-align: right block?

I don't know about the radio buttons on the right: in some kind of <span> perhaps, with "display: inline-block"? Or "white-space: pre"?

What kind of block-level tags (e.g. <p> or <div>) and/or other tags (e.g. <span> or <br/>) would you recommend?


Edit:

How about the following.

HTML uses <legend>, like HTML is supposed to and as recommended in the alistapart article:

<fieldset>
<legend>Car</legend>
<label><input type="radio" name="car" value="yes"/> Yes</label>
<label><input type="radio" name="car" value="no"/> No</label>
<label><input type="radio" name="car" value="maybe"/> Maybe</label>
</fieldset>

To make it easer for Firefox to access/position the contents of the <legend>, place it within a <span>:

<fieldset>
<legend><span>Car</span></legend>
<label><input type="radio" name="car" value="yes"/> Yes</label>
<label><input type="radio" name="car" value="no"/> No</label>
<label><input type="radio" name="car" value="maybe"/> Maybe</label>
</fieldset>

Then, use the browser-specific CSS described in Legends of Style Revised to position the contents of the span to left of the fieldset.

Does the CSS really have to be so complicated and browser-specific? What's the simplest CSS which ought theoretically to work, instead of the more-complicated CSS required to actually work with those imperfect browsers? If <legend> is hard to position then what's a good (semantic) alternative?

ChrisW
  • 54,973
  • 13
  • 116
  • 224

4 Answers4

8

This is what I usually do with my radio buttons and checkboxes. It allows the associated text to be clickable in most browsers without having to do any work, which makes the form a little easier to use. The CSS cursor change helps to alert the user to this feature.

CSS

label { cursor: pointer; }

HTML

<label><input type="radio" name="option" value="yes"> Yes</label>
<label><input type="radio" name="option" value="no"> No</label>
<label><input type="radio" name="option" value="maybe"> Maybe</label>

Alternatively, use a fieldset legend for cars and a ul for the list of radio buttons:

<fieldset>
    <legend>Cars</legend>
    <ul class="radio-list">
        <li><label><input type="radio" name="option" value="yes"> Yes</label></li>
        <li><label><input type="radio" name="option" value="no"> No</label></li>
        <li><label><input type="radio" name="option" value="maybe"> Maybe</label></li>
    </ul>
<fieldset>

CSS

.radio-list li { list-style: none; }

Stylizing a fieldset/legend to be consistent across browsers isn't too difficult; however, it does require one IE conditional if you want a border around the legend. The only extra HTML that is necessary is a wrapper span within the legend.

CSS

<style>
    fieldset {
        position: relative;
        border: 1px solid #000;
        background: #f8f8f8;
        padding: 1.6em 10px 0px;
        margin: 0;
    }
    legend {
        position: absolute;
        font-weight: bold;
        font-size: 1.2em;
    }
    legend span {
        position: absolute;
        top: -1.1em;
        white-space: nowrap;
    }

    /* This isn't necessary, just here for list aesthetics */
    ul, li {
        margin: 0;
        padding: 0;
        list-style-type: none;
    }
</style>

<!--[if IE]>
    <style>
    legend {
        border-bottom: 1px solid #000;
    }
    </style>
<![endif]-->

HTML

<fieldset>
    <legend><span>Did you enjoy your SO experience?</span></legend>
    <form>
        <ul>
            <li><label><input type="radio" name="option" value="yes"> Yes</label></li>
            <li><label><input type="radio" name="option" value="no"> No</label></li>
            <li><label><input type="radio" name="option" value="maybe"> Maybe</label></li>
        </ul>
    </form>
</fieldset>

That's about as simple as I can get it. Live example

Justin Johnson
  • 30,978
  • 7
  • 65
  • 89
  • In the first example, how do you get the labels to arrange vertically to the right of the legend? In the second example, is having `
      ` and `
    • `s a lot of extra display-related non-semantic markup?
    – ChrisW Jun 28 '10 at 15:17
  • @Chris: It's a list of radio buttons. It's *completely* semantic markup and entirely valid. What *isn't* valid is trying to turn it into a list by using CSS on the labels. Labels aren't block level elements by nature, use them accordingly. – Josh K Jun 28 '10 at 15:21
  • @Chris: I added a live example. Depending on *precisely* how you want your form laid out this may work. Needing the lineup the way you have indicated would mean removing the border around a fieldset and floating the legend left while providing the ul with an additional margin to compensate. – Josh K Jun 28 '10 at 15:36
  • @Chris: I updated that with a second form that styles it more like your original question. – Josh K Jun 28 '10 at 15:50
  • It is more like original the question; except that (using IE8 and using Firefox) the `` is above as well as to the left of the radio buttons. I'd prefer it to be level with the corresponding button[s] on the right, in order to match other things on the form (e.g. where a label on the left is level with a corresponding `` on the right). – ChrisW Jun 28 '10 at 16:04
  • @Chris: That page is bare. By bare I mean no CSS reset or the like. Including something like [Blueprint](http://www.blueprintcss.org) would probably alleviate all or some of those issues. – Josh K Jun 28 '10 at 16:25
  • @Josh I ammended my OP to reference an article which shows how to position a ``; but that CSS seems complicated to me, and browser-specific ... but using `` is probably the most semantically correct; so, what a dilemma. – ChrisW Jun 28 '10 at 16:36
  • @Chris: I included the blueprint styles, let me know if that fixes the rendering. – Josh K Jun 28 '10 at 16:41
  • It doesn't fix it, in either browser. http://www.tyssendesign.com.au/articles/css/legends-of-style/ suggests something more complicated. – ChrisW Jun 28 '10 at 16:58
  • @chrisw Adding `display:block` to `label`'s is perfectly reasonable. – Justin Johnson Jun 29 '10 at 07:07
  • @Justin Johnson I agree with adding `display:block` to `label`s is reasonable, is, but I don't know why you're suggesting it: doing that wouldn't help with getting the legend positioned to the left of the radio buttons. – ChrisW Jun 29 '10 at 19:19
  • Sorry, that should have been in response to JoshK's first comment. – Justin Johnson Jun 30 '10 at 00:20
0

Mmmm.... Car and Train should definitely be <label>s. Check out this classic A List Apart article for a really nice example: Prettier Accessible Forms

As for the radio button labels: Good question! I'd say <label> s again, but a <span> would do as well.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • 1
    @Pekka: interesting, the article uses a ` – Andy E Jun 28 '10 at 15:07
  • 1
    alistapart is using `
    `, with `` (not `
    – ChrisW Jun 28 '10 at 15:09
  • @Andy I think using `label for` won't work for each individual radio button because they all have the same name. Still, `label` is probably the best choice here. As @Chris correctly notes, ALA are using a `fieldset` for the radio options. Not sure whether that makes 100% sense to me. – Pekka Jun 28 '10 at 15:12
  • Unfortunately it's using `display:block` for the labels, so its markup ensures that the legend is above (not to the left of, which is what I want) all the radio buttons and their labels. – ChrisW Jun 28 '10 at 15:13
  • @ChrisW: `legend` is written on the `fieldset` border. – Amadan Jun 28 '10 at 15:15
  • @Amadan - you're right: so it is. Is the display of that configurable, or, must I therefore want to use something other than ``? – ChrisW Jun 28 '10 at 15:23
  • @Pekka — the `for` attribute keys off the `id`, not the `name`. – Quentin Jun 28 '10 at 15:24
  • A label can be associated with one, and only one input. You can't associate a label "Car" with the fields "Yes", "No" **and** "Maybe" – Quentin Jun 28 '10 at 15:25
  • @Pekka: `label for` looks up `id`, having same `name` doesn't matter. `label` is made for labelling boxes - they are small and clickable only with difficulty, so `label` extends the targeting area. – Amadan Jun 28 '10 at 15:25
  • @Pekka: the `for` is applicable to the `id` attribute, not the `name` attribute -- [spec](http://www.w3.org/TR/html401/interact/forms.html#h-17.9.1). Also, ALA are wrapping the label element around the input element instead, which I thought had issues in IE but I could be wrong. The ` – Andy E Jun 28 '10 at 15:25
  • @Andy @Amadan ah, makes sense. Wasn't aware it was possible to target `id` s as well. – Pekka Jun 28 '10 at 15:26
  • @David I see - that's why ALA are using the fieldset in their example. Thanks for the clarification. – Pekka Jun 28 '10 at 15:27
  • @Pekka — not *as well*. The for attribute does not target the name attribute, ever. Just the id attribute. – Quentin Jun 28 '10 at 15:27
  • 1
    @David @Andy hah, I've been doing this wrong for years now! :) I stand corrected. Cheers! – Pekka Jun 28 '10 at 15:33
0

css: (ugly class names need to be changed)

p.radio { height: 4em; }
label.top {
  display: block;
  width: 4em; /* or something else */
  float: left;
  text-align: right;
  padding-right: 1em;
  height: 4em;
}

html:

<p class="radio">
  <label class="top" for="car">Car:</label>
  <input type="radio" value="yes" name="car" id="car_y" />
  <label for="car_y">Yes</label><br />
  <input type="radio" value="no" name="car" id="car_n" />
  <label for="car_n">No</label><br />
  <input type="radio" value="maybe" name="car" id="car_m" />
  <label for="car_m">Maybe</label><br />
</p>

EDIT: didn't see the other answer. Using a fieldset instead of a paragraph and legend for the "top-level" label seems to be a good idea IMO.

EDIT2: according to comments, and I agree, using a list would be cleaner here. The new version would be :

css:

fieldset {
  border: 0;
  padding: 0;
}
legend {
  padding: 0 0.5em 0 0;
  margin: 0;
  display: block;
  width: 3.5em;
  float: left;
  text-align: right;
}
ul {
  margin: 0;
  padding: 0 0 0 4em;
}
ul li {
  list-style-type: none;
  list-style-position: outer;
}

html:

<fieldset>
  <legend>Car:</legend>
  <ul>
    <li>
      <input type="radio" value="yes" name="car" id="car_y" />
      <label for="car_y">Yes</label>
    </li>
    <li>
      <input type="radio" value="no" name="car" id="car_n" />
      <label for="car_n">No</label>
    </li>
    <li>
      <input type="radio" value="maybe" name="car" id="car_m" />
      <label for="car_m">Maybe</label>
    </li>
  </ul>
</fieldset>

That would be much more elegant. But even with display:block firefox doesn't seem to want to set the width of a legend element. Strange bug.

p4bl0
  • 3,846
  • 1
  • 22
  • 21
  • So you're getting the top-most legend to the left by doing `float: left`, instead of getting the radio buttons to the right using `display: inline-block`. Yea, that could be a good way to do it. – ChrisW Jun 28 '10 at 15:21
  • @Josh K - Why is it a list? Are `` element usually supposed to be contained within list items? – ChrisW Jun 28 '10 at 15:24
  • There is no element with the id *car*, so the first label is not associated with any form controls. – Quentin Jun 28 '10 at 15:26
  • @Chris: It doesn't need to be, but according to how you are presenting, it's a list of radio buttons. – Josh K Jun 28 '10 at 15:28
  • @David Dorward - That's true. What would you do to correct that: replace it with a ``? – ChrisW Jun 28 '10 at 15:29
  • legend, as per earlier answers – Quentin Jun 28 '10 at 15:33
  • @David It's difficult to position a legend to the left of the radio buttons: see e.g. [Legends of Style Revised](http://www.alistapart.com/articles/prettyaccessibleforms). – ChrisW Jun 28 '10 at 16:15
0

I'll use <fieldset>.

The difficulty with positioning a <label> in different browsers is described in the "Legends of Style Revised" article; so instead of using a <label> and trying to position it, I might use a <span class="label"> outside the <fieldset>.

ChrisW
  • 54,973
  • 13
  • 116
  • 224