hierarchies, taxonomies, categories, drill-downs, etc.

I searched all over the place for a tidy pattern to deal with displaying hierarchical data for selection (as in a set of categories and sub-categories or a taxonomy), and couldn’t find anything. I think everyone’s aware of how this can be done with AJAX, but I wanted something that would still work without needing Javascript or a round-trip to the server each time a parent category changed. Obviously that means storing the entire taxonomy on the page, which is only realistic for some uses of this sort of control, but it’s those uses I’m interested in.

My solution is to load the entire taxonomy into an unordered list and include a radio button in each list item. This shows the hierarchy clearly and lets the user select a node of any depth (a requirement in my case). I use some Javascript to hide the radio buttons and show/hide child lists based on clicks on the list items themselves, then check the radio buttons behind the scenes. I’m wondering if this is the best possible solution for my circumstances. My hope is that neatly organizing the data in this way makes it more accessible, but I’m no accessibility expert.

The HTML itself is pretty simple (excuse the junk data):

<div id="taxonomy">
		<li><input type="radio" name="ghj" value="A" /> A
				<li><input type="radio" name="ghj" value="I" /> I
						<li><input type="radio" name="ghj" value="1" /> 1
								<li><input type="radio" name="ghj" value="a" /> a</li>
								<li><input type="radio" name="ghj" value="b" /> b</li>
								<li><input type="radio" name="ghj" value="c" /> c</li>
								<li><input type="radio" name="ghj" value="d" /> d</li>
								<li><input type="radio" name="ghj" value="e" /> e</li>
						<li><input type="radio" name="ghj" value="2" /> 2</li>
						<li><input type="radio" name="ghj" value="3" /> 3</li>
						<li><input type="radio" name="ghj" value="4" /> 4</li>
						<li><input type="radio" name="ghj" value="5" /> 5</li>
				<li><input type="radio" name="ghj" value="II" /> II</li>
				<li><input type="radio" name="ghj" value="III" /> III
						<li><input type="radio" name="ghj" value="6" /> 6
								<li><input type="radio" name="ghj" value="f" /> f</li>
								<li><input type="radio" name="ghj" value="g" /> g</li>
								<li><input type="radio" name="ghj" value="h" /> h</li>
								<li><input type="radio" name="ghj" value="i" /> i</li>
								<li><input type="radio" name="ghj" value="j" /> j</li>
						<li><input type="radio" name="ghj" value="7" /> 7</li>
						<li><input type="radio" name="ghj" value="8" /> 8</li>
						<li><input type="radio" name="ghj" value="9" /> 9</li>
						<li><input type="radio" name="ghj" value="10" /> 10</li>
				<li><input type="radio" name="ghj" value="IV" /> IV</li>
				<li><input type="radio" name="ghj" value="V" /> V</li>
		<li><input type="radio" name="ghj" value="B" /> B</li>
		<li><input type="radio" name="ghj" value="C" /> C</li>
		<li><input type="radio" name="ghj" value="D" /> D</li>
		<li><input type="radio" name="ghj" value="E" /> E</li>
The finished product with some simple styling

The finished product with some simple styling

Styling is split up so that positioning the child lists doesn’t interfere with the display of the un-enhanced version:

	#taxonomy { padding: 50px; background-color: #fff; height: 300px; }
	#taxonomy ul {
		margin: 0px 0px 0px 10px;
		padding: 10px;
		border: 1px solid #ccc;
		-moz-border-radius: 10px;
		-webkit-border-radius: 10px;
		border-radius: 10px;
		list-style-type: none;
		background-color: #fff;
	#taxonomy ul.dyn {		
		position: absolute;
		left: 50px;
		top: 50px;
		height: 280px;
		width: 180px;
	#taxonomy ul ul { border-color: #fff; }
	#taxonomy ul.dyn ul
		position: absolute;
		top: 0px;
		left: 200px;
		display: none;
		height: 280px;
		width: 180px;
	#taxonomy ul.dyn li:hover {
		border: none;
		background-color: #eee;
		-moz-border-radius: 10px;
		-webkit-border-radius: 10px;
		border-radius: 10px;
		width: 100%;
		padding-right: 30px;
		z-index: -1;
	#taxonomy ul.dyn li > ul { background-color: #eee; border-color: #eee; }
	#taxonomy ul.dyn ul li:hover, #taxonomy ul.dyn ul li > ul { border-color: #ddd; background-color: #ddd; }
	#taxonomy ul.dyn ul ul li:hover, #taxonomy ul.dyn ul ul li > ul { border-color: #ccc; background-color: #ccc; }
	#taxonomy ul.dyn ul ul ul li:hover { width: auto; padding-right: 0px; }

Finally, some Javascript breaks the list up and provides its positioning:

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
	<script type="text/javascript">
	$(document).ready(function () {
		$("#taxonomy > ul").addClass("dyn");
		$("#taxonomy input").css("visibility","hidden");
		$("#taxonomy li").each(function (i) {
			$(this).bind("click",function(e) {
				var rad = $(this).children("input");
				return false;

Initially, I was using a noscript block to add this style: input:checked ~ ul {display:block;} and the only visual change the Javascript made was to hide the radio buttons (there was no “dyn” class). That works very well in modern browsers if your hierarchy is only two levels deep or users can only select from the lowest level, as in the classic example of vehicle make, model, and year. It didn’t work for my purposes, though, because users can select from any of four levels. It’s an easy change to make, though. The only thing to check is that IE6 is getting the correct styling, since it won’t recognize many of the selectors used here. I’m going to create a special script to handle that, but if you weren’t encumbered by that browser you could skip that step entirely.

Whew! So.. Is there a better way to accomplish this?


0 Responses to “hierarchies, taxonomies, categories, drill-downs, etc.”

  1. Leave a Comment

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

RSS Recent posts on the live version of this blog

  • An error has occurred; the feed is probably down. Try again later.

%d bloggers like this: