SitePoint Sponsor

User Tag List

Results 1 to 19 of 19
  1. #1
    SitePoint Guru tictike's Avatar
    Join Date
    Apr 2008
    Location
    Canada
    Posts
    863
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    labeling a radio group

    With a text input field I use the 'for' attribute of the label element to link it the 'id' of the input field.

    But what is the correct way to link a label to a radio group? Should the 'for' attribute of the label and 'name' attribute of the input match?

    -------------------
    hold on a min, let me give more info
    Last edited by tictike; Sep 27, 2008 at 10:32. Reason: edit

  2. #2
    SitePoint Guru tictike's Avatar
    Join Date
    Apr 2008
    Location
    Canada
    Posts
    863
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A form includes:

    <p>Gender</p>
    <label for="male">Male</label><input type="radio" name="gender" id="male">
    <label for="female">Female</label><input type="radio" name="gender" id="female">

    Originally I was trying to figure out how to markup the work 'Gender'. Looking at it again, I suppose a p element is fine.

  3. #3
    SitePoint Wizard silver trophybronze trophy
    Join Date
    Jul 2008
    Location
    New York, NY
    Posts
    1,432
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    <form action="/">
    	<fieldset>
    		<legend>Gender</legend>
    		
    		<label for="male" title="Male Gender">Male</label>
    		<input type="radio" name="gender" id="male" checked="checked" /><br />
    		
    		<label for="female" title="Female Gender">Female</label>
    		<input type="radio" name="gender" id="female" />
    	</fieldset>
    	
    	<fieldset>
    		<legend>Education</legend>
    		
    		<label for="high-school" title="High School Education">High School</label>
    		<input type="radio" name="education" id="high-school" /><br />
    		
    		<label for="college" title="College Education">College</label>
    		<input type="radio" name="education" id="college" checked="checked" /><br />
    		
    		<label for="neither" title="No Education">Neither</label>
    		<input type="radio" name="education" id="neither" />
    	</fieldset>
    </form>

  4. #4
    SitePoint Wizard silver trophybronze trophy
    Join Date
    Jul 2008
    Location
    New York, NY
    Posts
    1,432
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There are a million different ways you can do this. I just would not use a p tag because 'gender' is not a paragraph.

  5. #5
    SitePoint Author silver trophybronze trophy

    Join Date
    Nov 2004
    Location
    Ankh-Morpork
    Posts
    12,158
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by tictike View Post
    But what is the correct way to link a label to a radio group? Should the 'for' attribute of the label and 'name' attribute of the input match?
    No, you can't link a label to more than one element.

    To provide a heading for a radio group, the best way is to use a fieldset and a legend, as cooper.semantics showed.
    Birnam wood is come to Dunsinane

  6. #6
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    The for attribute must match an id attribute, that id attribute being the element that will gain the focus when the label is clicked.

    It's possible to do without the for attribute by specifying an implicit association between the label and the input, however IE6 won't understand the association.

    Code html4strict:
    <!-- explicitly associated label -->
    <label for="name">Name</label>
    <input type="text" name="name" id="name">
     
    <!-- implicitly associated label -->
    <label>Name <input type="text" name="name"></label>

    If you were to do that with a radio group then only the first input element would be associated with the label. However, using a label for each radio option is perfectly okay.

    Code html4strict:
    <p>Make your choice:</p>
    <p>
        <label><input type="text" name="yes"> Yes</label>
        <label><input type="text" name="no"> No</label>
    </p>

    or in longhand

    Code html4strict:
    <p>Make your choice:</p>
    <p>
        <input type="text" name="yes" id="yes">
        <label for="yes">Yes</label>
        <input type="text" name="no" id="no">
        <label for="no">No</label>
    </p>
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  7. #7
    SitePoint Addict rochow's Avatar
    Join Date
    Oct 2006
    Location
    Queensland, Australia
    Posts
    300
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code:
    <label><input type="text" name="yes"> Yes</label>
    I read somewhere that some screenreaders choke when the actual field is INSIDE the label instead of outside it, I'd post the link if I could find it. Not to mention its not correct - the <label> shouldn't include the actual input, the label is meant to only have the description of the input/select/etc

  8. #8
    SitePoint Evangelist Karpie's Avatar
    Join Date
    Jul 2007
    Location
    Perth, Australia
    Posts
    445
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by AutisticCuckoo View Post
    To provide a heading for a radio group, the best way is to use a fieldset and a legend, as cooper.semantics showed.
    Can fieldsets and legends be nested, then? I've always used them for grouping together multiple different form inputs, things like 'Address Details' which then contains text fields for street name, drop down for state, etc..... if that grouping then needs to have an inner grouping for radio buttons, is that even valid?

  9. #9
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,789
    Mentioned
    25 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by rochow View Post
    Code:
    <label><input type="text" name="yes"> Yes</label>
    I read somewhere that some screenreaders choke when the actual field is INSIDE the label instead of outside it, I'd post the link if I could find it. Not to mention its not correct - the <label> shouldn't include the actual input, the label is meant to only have the description of the input/select/etc
    There are also some older browsers where the reverse is true - the 'for' attribute is not recognised and the label will only work if it wraps the form field. That is probably the reason why people started using that invalid nesting - because it worked in more browsers. Now that hardly anyone uses those old browsers any more there is no need to continue to nest the field (after all the field is NOT a part of the label and so shouldn't be contained within it regardless of whether it works or not it is not semanticly correct).
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  10. #10
    SitePoint Addict rochow's Avatar
    Join Date
    Oct 2006
    Location
    Queensland, Australia
    Posts
    300
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There are also some older browsers where the reverse is true
    Haha, when I worked with older browsers all I used were tables and pretty much everything that is now deprecated (yay for the awesome schooling system which teaches the wrong way of doing everything!)

    It still works when aligning radio/label text next to each other - however that's presentational, not semantic.

  11. #11
    SitePoint Author silver trophybronze trophy

    Join Date
    Nov 2004
    Location
    Ankh-Morpork
    Posts
    12,158
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Karpie View Post
    Can fieldsets and legends be nested, then?
    Yes, a fieldset can contain other fieldsets (and each one must have a legend).

    Code HTML4Strict:
    <fieldset>
      <legend>Student Information</legend>
     
      <fieldset>
        <legend>Sex</legend>
        <input type="radio" id="female"...> <label for="female">Female</label>
        <input type="radio" id="male"...> <label for="male">Male</label>
      </fieldset>
     
      <fieldset>
        <legend>Age</legend>
        <input type="radio" id="age6-8"...> <label for="age6-8">6 to 8</label>
        <input type="radio" id="age9-11"...> <label for="age9-11">9 to 11</label>
        <input type="radio" id="age12-14"...> <label for="age12-14">12 to 14></label>
      </fieldset>
    </fieldset>
    Birnam wood is come to Dunsinane

  12. #12
    SitePoint Evangelist Karpie's Avatar
    Join Date
    Jul 2007
    Location
    Perth, Australia
    Posts
    445
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ah, excellent, thanks

  13. #13
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by felgall View Post
    Now that hardly anyone uses those old browsers any more there is no need to continue to nest the field (after all the field is NOT a part of the label and so shouldn't be contained within it regardless of whether it works or not it is not semanticly correct).
    The whole purpose of the label field is to attach information to controls.

    It smells bad to have a form filled with id attributes when their only purpose is to associate the input to the label. The specs (linked above) already provide a mechanism in which to associate the label with the input field through implicit association.

    For usability reasons though it is important that IE6 doesn't suffer from not understanding implicit association, so for that reason using explicit association via for and id attributes is a must.

    For me personally though, it's about time though to leave IE6 in the dust. It's more tempting to leave the code nice and clean and use javascript to provide the explicit association instead.

    Code javascript:
    (function explicitLabelAssociation() {
    	function forEach(array, fn) {
    		var i;
    		for (i = 0; i < array.length; i += 1) {
    			fn(array[i], i);
    		}
    	}
    	var labels = document.getElementsByTagName('label');
    	forEach(labels, function (label) {
    		var input = label.getElementsByTagName('input')[0],
    			id = input.name;
    		input.setAttribute('id', id);
    		label.setAttribute('for', id);
    	});
    }());

    or taking it a step further, checking if the id has already been taken and incrementing the identifier until one that hasn't been taken is found.

    Code javascript:
    (function explicitLabelAssociation() {
    	function forEach(array, fn) {
    		var i;
    		for (i = 0; i < array.length; i += 1) {
    			fn(array[i], i);
    		}
    	}
    	function incrementIndex(name) {
    		var regex = /^(.*)(\d+)$/,
    			match,
    			term,
    			index,
    			newName;
    		if (regex.test(name)) {
    			match = regex.match(name);
    			term = match[1];
    			index = parseInt(match[2], 10) + 1;
    			newName = term + index;
    		} else {
    			newName = name + '0';
    		}
    		return newName;
    	}
    	var labels = document.getElementsByTagName('label');
    	forEach(labels, function (label) {
    		var input = label.getElementsByTagName('input')[0],
    			id = input.name;
    		while (document.getElementById(id)) {
    			id = incrementIndex(name);
    		}
    		input.setAttribute('id', id);
    		label.setAttribute('for', id);
    	});
    }());
    Last edited by paul_wilkins; Oct 2, 2008 at 15:36.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  14. #14
    SitePoint Wizard silver trophybronze trophy
    Join Date
    Jul 2008
    Location
    New York, NY
    Posts
    1,432
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Nice script Paul

    Do you mind if I use it?

  15. #15
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    Yes, please use it.

    There was a subtle bug in the incrementIndex function (now updated though) regarding if the index number also appears in the same name (season2episode2) then the split will perform it at the wrong location.

    A more robust way is to capture both the term and the index from the regex itself.

    Here's an updated version of the incrementIndex function, which I'll use to update the original posting that it occured in as well.

    Code javascript:
    function incrementIndex(name) {
    	var regex = /^(.*)(\d+)$/,
    		match,
    		term,
    		index,
    		newName;
    	if (regex.test(name)) {
    		match = regex.match(name);
    		term = match[1];
    		index = parseInt(match[2], 10) + 1;
    		newName = term + index;
    	} else {
    		newName = name + '0';
    	}
    	return newName;
    }

    Though I'm generally against browser detection due future-proofing and difficulties in doing it properly, there is one technique that should be appropriate in this instance, and that's to use IE conditional comments so that the script can be targeted explicitly at IE browsers less than IE7

    First you place the script inside comment tags which prevents other browsers from running it, then specify a condition (that only IE understands) so that it's targeted where you need it to be.

    Code html4strict:
    <!--[if lt IE 7]>
    <script src="explicitLabelAssociation.js"> </script>
    <![endif]-->
    Last edited by paul_wilkins; Oct 2, 2008 at 15:49.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  16. #16
    Programming Since 1978 silver trophybronze trophy felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, NSW, Australia
    Posts
    16,789
    Mentioned
    25 Post(s)
    Tagged
    1 Thread(s)
    The disadvantage of using JavaScript to attach the labels to the fields that they refer to is that the people using a web reader who are the people most likely to actually need to have their browser know what label goes with what field so as it can tell them (since they don't get the visual clues) are the same pgroup who are most likely to have JavaScript disabled or not supported at all by their screen reader. That effectively removes the usefulness of having the label in the first place for the 5&#37; of your visitors who are most likely to need it if you create the association via JavaScript. These are also the browsers that don't like having the form field nested inside the label and so a separate label field with the for/id hard coded in the HTML is the only way to make the label truly accessible to the people who need it most.
    Stephen J Chapman

    javascriptexample.net, Book Reviews, follow me on Twitter
    HTML Help, CSS Help, JavaScript Help, PHP/mySQL Help, blog
    <input name="html5" type="text" required pattern="^$">

  17. #17
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    Exactly, for usability reasons you must link the label using the for attribute with the input's identifier. I don't like coding that way, it smells bad to have so many identifiers in the form, but if usability is paramount then it has to be put up with.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  18. #18
    SitePoint Wizard silver trophybronze trophy
    Join Date
    Jul 2008
    Location
    New York, NY
    Posts
    1,432
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by pmw57 View Post
    Yes, please use it.

    There was a subtle bug in the incrementIndex function (now updated though) regarding if the index number also appears in the same name (season2episode2) then the split will perform it at the wrong location.

    A more robust way is to capture both the term and the index from the regex itself.

    Here's an updated version of the incrementIndex function, which I'll use to update the original posting that it occured in as well.

    Code javascript:
    function incrementIndex(name) {
    	var regex = /^(.*)(\d+)$/,
    		match,
    		term,
    		index,
    		newName;
    	if (regex.test(name)) {
    		match = regex.match(name);
    		term = match[1];
    		index = parseInt(match[2], 10) + 1;
    		newName = term + index;
    	} else {
    		newName = name + '0';
    	}
    	return newName;
    }

    Though I'm generally against browser detection due future-proofing and difficulties in doing it properly, there is one technique that should be appropriate in this instance, and that's to use IE conditional comments so that the script can be targeted explicitly at IE browsers less than IE7

    First you place the script inside comment tags which prevents other browsers from running it, then specify a condition (that only IE understands) so that it's targeted where you need it to be.

    Code html4strict:
    <!--[if lt IE 7]>
    <script src="explicitLabelAssociation.js"> </script>
    <![endif]-->
    Thanks

  19. #19
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,688
    Mentioned
    100 Post(s)
    Tagged
    4 Thread(s)
    After some refactoring here is the explicitLabelAssociation function

    Code javascript:
    (function explicitLabelAssociation() {
    	var labels = document.getElementsByTagName('label');
    	forEach(labels, setExplicitLabel);
    	function forEach(array, fn) {
    		var i;
    		for (i = 0; i < array.length; i += 1) {
    			fn(array[i], i);
    		}	
    	}
    	function setExplicitLabel(label) {
    		var input = label.getElementsByTagName('input')[0],
    			id = nextAvailableId(input.name);
    		label.setAttribute('for', id);
    		input.setAttribute('id', id);
    	}
    	function nextAvailableId(name) {
    		var id = name;
    		while (document.getElementById(id)) {
    			id = increaseIndexOfTerm(id);
    		}
    	}
    	function increaseIndexOfTerm(id) {
    		var newId = splitIntoTermAndIndex(id);
    		return newId.term + new String(newId.index + 1);
    	}
    	function splitIdIntoTermAndIndex(id) {
    		var split = getTermAndIndex(id);
    		if (!split) {
    			return {'term': id, 'index': 0};
    		} else {
    			return {'term': split[1], 'index': toInteger(split[2])};
    		}
    	}
    	function getTermAndIndex(id) {
    		return id.match(/^(.*)(\d+)$/);
    	}
    	function toInteger(number) {
    		return parseInt(number, 10);
    	}
    }());
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •