diff --git link.css link.css
index 7bdec9e..8c1119f 100644
--- link.css
+++ link.css
@@ -3,6 +3,11 @@ div.link-field-column {
   width: 48%;
 }
 
+div.link-field-compact div.link-field-column {
+  width: 33%;
+}
+
 div.link-field-column .form-text {
   width: 95%;
 }
+
diff --git link.module link.module
index 2561929..3a1d7f8 100644
--- link.module
+++ link.module
@@ -46,7 +46,7 @@ function link_field_info() {
   return array(
     'link' => array(
       'label' => t('Link'),
-      'description' => t('Store a title, href, and attributes in the database to assemble a link.'),
+      'description' => t('Store a title, href, description and attributes in the database to assemble a link.'),
     ),
   );
 }
@@ -97,6 +97,27 @@ function link_field_settings($op, $field) {
         '#size' => '46',
       );
 
+      $description_options = array(
+        'optional' => t('Optional Description'),
+        'required' => t('Required Description'),
+        'value' => t('Static Description: '),
+        'none' => t('No Description'),
+      );
+
+      $form['link_description'] = array(
+        '#type' => 'radios',
+        '#title' => t('Link Description'),
+        '#default_value' => isset($field['link_description']) && ($field['link_description'] !== '') ? $field['link_description'] : 'optional',
+        '#options' => $description_options,
+        '#description' => t('If the link description is optional or required, a field will be displayed to the end user. If the link description is static, the link will always use the same description. If <a href="http://drupal.org/project/token">token module</a> is installed, the static description value may use any other node field as its value. Static and token-based descriptions may include most inline XHTML tags such as <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc.'),
+      );
+
+      $form['link_description_value'] = array(
+        '#type' => 'textfield',
+        '#default_value' => $field['link_description_value'],
+        '#size' => '46',
+      );
+
       // Add token module replacements if available
       if (module_exists('token')) {
         $form['tokens'] = array(
@@ -160,29 +181,45 @@ function link_field_settings($op, $field) {
         '#description' => t('When output, this link will have this class attribute. Multiple classes should be separated by spaces.'),
         '#default_value' => empty($field['attributes']['class']) ? '' : $field['attributes']['class'],
       );
+
+      $attr_title_options = array(
+        'link_description' => t('Use Description Field'),
+        'value' => t('Static Title Attribute: '),
+        'none' => t('No Title Attribute'),
+      );
+
       $form['attributes']['title'] = array(
+        '#type' => 'radios',
         '#title' => t("Link 'title' Attribute"),
-        '#type' => 'textfield',
-        '#field_prefix' => 'title = "',
-        '#field_suffix' => '"',
+        '#default_value' => isset($field['attributes']['title']) ? $field['attributes']['title'] : 'link_description',
+        '#options' => $attr_title_options,
         '#description' => t('When output, links will use this "title" attribute (when different from the link text). Read <a href="http://www.w3.org/TR/WCAG10-HTML-TECHS/#links">WCAG 1.0 Guidelines</a> for links comformances. Tokens values will be evaluated.'),
-        '#default_value' => empty($field['attributes']['title']) ? '' : $field['attributes']['title'],
       );
+
+      $form['attr_title_value'] = array(
+        '#type' => 'textfield',
+        '#default_value' => empty($field['attr_title_value']) ? '' : $field['attr_title_value'],
+      );
+
       return $form;
 
     case 'validate':
       if ($field['title'] == 'value' && empty($field['title_value'])) {
         form_set_error('title_value', t('A default title must be provided if the title is a static value'));
       }
+      if ($field['link_description'] == 'value' && empty($field['link_description_value'])) {
+        form_set_error('link_description_value', t('A default link description must be provided if the link description is a static value'));
+      }
       break;
 
     case 'save':
-      return array('attributes', 'display', 'url', 'title', 'title_value', 'enable_tokens', 'validate_url');
+      return array('attributes', 'display', 'url', 'title', 'title_value', 'link_description', 'link_description_value', 'attr_title_value', 'enable_tokens', 'validate_url');
 
     case 'database columns':
       return array(
         'url' => array('type' => 'varchar', 'length' => LINK_URL_MAX_LENGTH, 'not null' => FALSE, 'sortable' => TRUE),
         'title' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
+        'link_description' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
         'attributes' => array('type' => 'text', 'size' => 'medium', 'not null' => FALSE),
       );
 
@@ -202,7 +239,22 @@ function theme_link_field_settings($form) {
   // Set Static Title radio option to include the title_value textfield.
   $form['title']['value'] = array('#value' => '<div class="container-inline">'. $title_checkbox . $title_value .'</div>');
 
-  // Reprint the title radio options with the included textfield.
+
+  $description_value = drupal_render($form['link_description_value']);
+  $description_checkbox = drupal_render($form['link_description']['value']);
+
+  // Set Static Description radio option to include the description_value textfield.
+  $form['link_description']['value'] = array('#value' => '<div class="container-inline">'. $description_checkbox . $description_value .'</div>');
+
+
+  $attr_title_value = drupal_render($form['attr_title_value']);
+  $attr_title_checkbox = drupal_render($form['attributes']['title']['value']);
+
+  // Set Static Title Attribute radio option to include the attr_title_value textfield.
+  $form['attributes']['title']['value'] = array('#value' => '<div class="container-inline">'. $attr_title_checkbox . $attr_title_value .'</div>');
+
+
+  // Reprint the radio options with the included textfields.
   return drupal_render($form);
 }
 
@@ -213,7 +265,6 @@ function link_content_is_empty($item, $field) {
   if (empty($item['title']) && empty($item['url'])) {
     return TRUE;
   }
-  return FALSE;
 }
 
 /**
@@ -318,6 +369,10 @@ function _link_validate(&$item, $delta, $field, $node, &$optional_field_found) {
     if ($field['title'] == 'required' && strlen(trim($item['title'])) == 0) {
       form_set_error($field['field_name'] .']['. $delta .'][title', t('Titles are required for all links.'));
     }
+    // Require a description for the link if necessary.
+    if ($field['link_description'] == 'required' && strlen(trim($item['link_description'])) == 0) {
+      form_set_error($field['field_name'] .']['. $delta .'][link_description', t('Descriptions are required for all links.'));
+    }
   }
   // Require a link if we have a title.
   if ($field['url'] !== 'optional' && strlen($item['title']) > 0 && strlen(trim($item['url'])) == 0) {
@@ -327,6 +382,8 @@ function _link_validate(&$item, $delta, $field, $node, &$optional_field_found) {
   if ($field['url'] == 'optional' && $field['title'] == 'optional' && (strlen(trim($item['url'])) != 0 || strlen(trim($item['title'])) != 0)) {
     $optional_field_found = TRUE;
   }
+
+  return FALSE;
 }
 
 /**
@@ -395,6 +452,16 @@ function _link_sanitize(&$item, $delta, &$field, &$node) {
   else {
     $title = $item['title'];
   }
+
+  // Use the description defined at the field level.
+  if ($field['link_description'] == 'value' && strlen(trim($field['link_description_value']))) {
+    $description = $field['link_description_value'];
+  }
+  // Use the description defined by the user at the widget level.
+  else {
+    $description = $item['link_description'];
+  }
+
   // Replace tokens. - originally we only did it for value titles.
   if ($field['enable_tokens'] && module_exists('token')) {
     // Load the node if necessary for nodes in views.
@@ -408,6 +475,18 @@ function _link_sanitize(&$item, $delta, &$field, &$node) {
   }
   $item['display_title'] = empty($title) ? $item['display_url'] : $title;
 
+  // Replace tokens for description field.
+  if (module_exists('token') && ($field['link_description'] == 'value' || $field['enable_tokens'])) {
+    // Load the node if necessary for nodes in views.
+    $token_node = isset($node->nid) ? node_load($node->nid) : $node;
+    $description = filter_xss(token_replace($description, 'node', $token_node), array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+    $item['html'] = TRUE;
+  }
+  elseif ($field['link_description'] == 'value') {
+    $description = filter_xss($description, array('b', 'br', 'code', 'em', 'i', 'img', 'span', 'strong', 'sub', 'sup', 'tt', 'u'));
+    $item['html'] = TRUE;
+  }
+
   if (!isset($item['attributes'])) {
     $item['attributes'] = array();
   }
@@ -441,16 +520,32 @@ function _link_sanitize(&$item, $delta, &$field, &$node) {
   if ($type != LINK_EXTERNAL && $type != LINK_NEWS && strpos($item['attributes']['rel'], 'nofollow') !== FALSE) {
     $item['attributes']['rel'] = str_replace('nofollow', '', $item['attributes']['rel']);
   }
-  // Some old field data may have $element['#item']['attributes']['rel'] as an array, which will cause errors:
-  if (is_array($element['#item']['attributes']['rel'])) {
-    unset($element['#item']['attributes']['rel']);
+  // Some old field data may have $item['attributes']['rel'] as an array, which will cause errors:
+  if (is_array($item['attributes']['rel'])) {
+    unset($item['attributes']['rel']);
+  }
+
+  // Handle "title" link attribute.
+
+  // Use the title attribute defined at the field level.
+  if ($field['attributes']['title'] == 'value' && strlen(trim($field['attr_title_value']))) {
+    $attr_title = $field['attr_title_value'];
+  }
+  elseif ($field['attributes']['title'] == 'link_description' && $description) {
+    $attr_title = $description;
+  }
+  // Use the title attribute defined by the user at the widget level.
+  else {
+    $attr_title = $item['attributes']['title'];
   }
 
-  // Handle "title" link attribute
-  if ($field['enable_tokens'] && !empty($item['attributes']['title']) && module_exists('token')) {
+  if ($field['enable_tokens'] && !empty($attr_title) && module_exists('token')) {
     // Load the node (necessary for nodes in views).
     $token_node = isset($node->nid) ? node_load($node->nid) : $node;
-    $item['attributes']['title'] = token_replace($item['attributes']['title'], 'node', $token_node);
+    $item['attributes']['title'] = token_replace($attr_title, 'node', $token_node);
+  }
+  else {
+    $item['attributes']['title'] = $attr_title;
   }
 
   // Remove title attribute if it's equal to link text.
@@ -476,6 +571,9 @@ function link_theme() {
     'link_formatter_default' => array(
       'arguments' => array('element' => NULL),
     ),
+    'link_formatter_descbefore' => array(
+      'arguments' => array('element' => NULL),
+    ),
     'link_formatter_plain' => array(
       'arguments' => array('element' => NULL),
     ),
@@ -511,18 +609,25 @@ function theme_link($element) {
     if (isset($element['url']) && isset($element['title'])) {
       $element['url']['#title'] = $element['#title'] .' '. $element['url']['#title'];
       $element['title']['#title'] = $element['#title'] .' '. $element['title']['#title'];
+      $element['link_description']['#title'] = $element['#title'] .' '. $element['link_description']['#title'];
     }
     elseif ($element['url']) {
       $element['url']['#title'] = $element['#title'];
     }
   }
 
+  $classes = array('link-field-subrow','clear-block');
+  if(isset($element['link_description'])) {$classes[] = 'link-field-compact';}
+
   $output = '';
-  $output .= '<div class="link-field-subrow clear-block">';
+  $output .= '<div class="' . implode(' ',$classes) . '">';
   if (isset($element['title'])) {
     $output .= '<div class="link-field-title link-field-column">'. theme('textfield', $element['title']) .'</div>';
   }
   $output .= '<div class="link-field-url'. (isset($element['title']) ? ' link-field-column' : '') .'">'. theme('textfield', $element['url']) .'</div>';
+  if (isset($element['link_description'])) {
+    $output .= '<div class="link-field-description link-field-column">'. theme('textfield', $element['link_description']) .'</div>';
+  }
   $output .= '</div>';
   if (!empty($element['attributes']['target'])) {
     $output .= '<div class="link-attributes">'. theme('checkbox', $element['attributes']['target']) .'</div>';
@@ -579,6 +684,15 @@ function link_process($element, $edit, $form_state, $form) {
        '#default_value' => isset($element['#value']['title']) ? $element['#value']['title'] : NULL,
      );
    }
+   if ($field['link_description'] != 'none' && $field['link_description'] != 'value') {
+     $element['link_description'] = array(
+       '#type' => 'textfield',
+       '#maxlength' => '255',
+       '#title' => t('Description'),
+       '#required' => FALSE,
+       '#default_value' => isset($element['#value']['link_description']) ? $element['#value']['link_description'] : NULL,
+     );
+   }
 
    // Initialize field attributes as an array if it is not an array yet.
    if (!is_array($field['attributes'])) {
@@ -604,7 +718,12 @@ function link_process($element, $edit, $form_state, $form) {
 function link_field_formatter_info() {
   return array(
     'default' => array(
-      'label' => t('Title, as link (default)'),
+      'label' => t('Title, as link, with description after (default).'),
+      'field types' => array('link'),
+      'multiple values' => CONTENT_HANDLE_CORE,
+    ),
+    'descbefore' => array(
+      'label' => t('Title, as link, with description before, as label'),
       'field types' => array('link'),
       'multiple values' => CONTENT_HANDLE_CORE,
     ),
@@ -645,13 +764,29 @@ function link_field_formatter_info() {
  * Theme function for 'default' text field formatter.
  */
 function theme_link_formatter_default($element) {
+  $description = $element['#item']['link_description'] ? ' <span class="field-type-link-description">' . check_plain($element['#item']['link_description']) . '</span>' : '';
+  // Display a normal link if both title and URL are available.
+  if (!empty($element['#item']['display_title']) && !empty($element['#item']['url'])) {
+    return l($element['#item']['display_title'], $element['#item']['url'], $element['#item']) . $description;
+  }
+  // If only a title, display the title.
+  elseif (!empty($element['#item']['display_title'])) {
+    return check_plain($element['#item']['display_title']) . $description;
+  }
+}
+
+/**
+ * Theme function for 'description before' text field formatter.
+ */
+function theme_link_formatter_descbefore($element) {
+  $description = $element['#item']['link_description'] ? ' <span class="field-type-link-description">' . check_plain($element['#item']['link_description']) . '</span>' . ": " : '';
   // Display a normal link if both title and URL are available.
   if (!empty($element['#item']['display_title']) && !empty($element['#item']['url'])) {
-    return l($element['#item']['display_title'], $element['#item']['url'], $element['#item']);
+    return $description . l($element['#item']['display_title'], $element['#item']['url'], $element['#item']);
   }
   // If only a title, display the title.
   elseif (!empty($element['#item']['display_title'])) {
-    return check_plain($element['#item']['display_title']);
+    return $description . check_plain($element['#item']['display_title']);
   }
 }
 
@@ -714,7 +849,8 @@ function link_token_list($type = 'all') {
 
     $tokens['link']['url'] = t("Link URL");
     $tokens['link']['title'] = t("Link title");
-    $tokens['link']['view'] = t("Formatted html link");
+    $tokens['link']['link_description'] = t("Link description");
+    $tokens['link']['view'] = t("Formatted html link w/description");
 
     return $tokens;
   }
@@ -726,6 +862,7 @@ function link_token_values($type, $object = NULL) {
 
     $tokens['url'] = $item['url'];
     $tokens['title'] = $item['title'];
+    $tokens['link_description'] = $item['link_description'];
     $tokens['view'] = isset($item['view']) ? $item['view'] : '';
 
     return $tokens;
diff --git views/link.views.inc views/link.views.inc
index e138110..859ee14 100644
--- views/link.views.inc
+++ views/link.views.inc
@@ -73,6 +73,37 @@ function link_views_content_field_data($field) {
       'allow_empty' => TRUE,
     ),
   );
+  // Build out additional views data for the link "description" field.
+  $data[$table_alias][$field['field_name'] .'link_description'] = array(
+    'group' => t('Content'),
+    'title' => t('@label description', array('@label' => t($field_types[$field['type']]['label']))) .': '. t($field['widget']['label']) .' ('. $field['field_name'] .')',
+    'help' =>  $data[$table_alias][$field['field_name'] .'_url']['help'],
+    'argument' => array(
+      'field' => $db_info['columns']['link_description']['column'],
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_argument_string',
+      'click sortable' => TRUE,
+      'name field' => '', // TODO, mimic content.views.inc :)
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+    'filter' => array(
+      'field' => $db_info['columns']['link_description']['column'],
+      'title' => t('@label description', array('@label' => t($field_types[$field['type']]['label']))),
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_filter_string',
+      'additional fields' => array(),
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+    'sort' => array(
+      'field' => $db_info['columns']['link_description']['column'],
+      'tablename' => $db_info['table'],
+      'handler' => 'content_handler_sort',
+      'content_field_name' => $field['field_name'],
+      'allow_empty' => TRUE,
+    ),
+  );
 
   // Build out additional Views filter for the link "protocol" pseudo field.
   $data[$table_alias][$field['field_name'] .'_protocol'] = array(
