Drupal: Adding a Unique ID to a Themed List Wrapper

Or, how to style lists like a boss.

Well, well, well. We don't usually post much geeky tech stuff here. But rest assured, there's plenty of geekery going on behind the scenes here at The Vacuum. Let's crack open the door for a minute here & post something techy. Who knows, it might be just the thing you're looking for some day. Stranger things have happened.

The other day I needed to output a couple of lists from a custom Drupal 7 module using theme_item_list(), and I realized styling them properly would be much easier if they each had a unique ID on their wrapper div element instead of just the generic class="item-list".

Here's how I added an ID by overriding the function in my theme's template.php.

One gotcha: I was originally calling theme_item_list() directly, which meant my overridden function wasn't being called. As indicated here, I switched to calling theme('item_list') instead, and voila, custom IDs for my list wrappers. Also, don't forget to clear your cache!

function MYTHEME_item_list($variables) {
  $items = $variables['items'];
  $title = $variables['title'];
  $type = $variables['type'];
  $attributes = $variables['attributes'];
  // KM: Check for an item in the $variables array called 'container_id'
  // KM: If not found, default to a blank string.
  $container_id = isset($variables['container_id']) ? ' id="' . $variables['container_id'] . '"' : '';

  // Only output the list container and title, if there are any list items.
  // Check to see whether the block title exists before adding a header.
  // Empty headers are not semantic and present accessibility challenges.
  // KM: Add the container_id attribute to the list element container
  $output = '<div class="item-list"' . $container_id . '>';
  if (isset($title) && $title !== '') {
    $output .= '<h3>' . $title . '</h3>';
  }

  if (!empty($items)) {
    $output .= "<$type" . drupal_attributes($attributes) . '>';
    $num_items = count($items);
    foreach ($items as $i => $item) {
      $attributes = array();
      $children = array();
      $data = '';
      if (is_array($item)) {
        foreach ($item as $key => $value) {
          if ($key == 'data') {
            $data = $value;
          }
          elseif ($key == 'children') {
            $children = $value;
          }
          else {
            $attributes[$key] = $value;
          }
        }
      }
      else {
        $data = $item;
      }
      if (count($children) > 0) {
        // Render nested list.
        $data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
      }
      if ($i == 0) {
        $attributes['class'][] = 'first';
      }
      if ($i == $num_items - 1) {
        $attributes['class'][] = 'last';
      }
      $output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
    }
    $output .= "</$type>";
  }
  $output .= '</div>';
  return $output;
}

I use it like this:

$output .= theme('item_list', array(
    'items' => $typeList,
    'title' => $typeName,
    'type' => 'ul',
    'attributes' => array('id' => 'scope-list'),
    'container_id' => 'type-list-wrapper',
    )
  );

And here's the output:

<div class="item-list" id="type-list-wrapper">
  <h3>Type:</h3>
  <ul id="type-list">
    <li class="first"><a href="/projects">All</a></li>
    <li><a href="/projects/residential/">Residential</a></li>
    <li class="last"><a href="/projects/commercial/" class="active">Commercial</a></li>
  </ul>
</div>

There you have it, a nice unique ID on our list wrapper, just waiting for some CSS to rain down upon it. Neat!

Posted by kris
August 28, 2012 - 4:31pm

TAGS: Dev / Drupal / Tech