diff --git node_reference/node_reference.module node_reference/node_reference.module
index 64f19cb..eb5763e 100644
--- node_reference/node_reference.module
+++ node_reference/node_reference.module
@@ -29,7 +29,14 @@ function node_reference_field_info() {
     'node_reference' => array(
       'label'             => t('Node reference'),
       'description'       => t('This field stores the ID of a related node as an integer value.'),
-      'settings'          => array('referenceable_types' => array()),
+      'settings'          => array(
+        'referenceable_types' => array(),
+        'view' => array(
+          'view_name' => '',
+          'display_name' => '',
+          'args' => array(),
+        ),
+      ),
       // It probably make more sense to have the referenceable types be per-field than per-instance
       // 'instance settings' => array('referenceable_types' => array()),
       'default_widget'    => 'options_select', //  node_reference_autocomplete',
@@ -79,10 +86,77 @@ function node_reference_field_settings_form($field, $instance, $has_data) {
       : array(),
     '#options'       => array_map('check_plain', node_type_get_names()),
   );
+
+  if (module_exists('views')) {
+    $form['view'] = array(
+       '#type' => 'fieldset',
+       '#title' => t('Views - Nodes that can be referenced'),
+       '#collapsible' => TRUE,
+       '#collapsed' => empty($settings['view']['view_name']),
+       '#description' => t('The list of nodes that can be referenced can provided by a view (Views module) using the "References" display type.'),
+       // The value of the 'view_and_display' select below will need to be split
+       // into 'view_name' and 'view_display' in the final submitted values, so
+       // we massage the data at validate time (not ideal).
+       '#element_validate' => array('_node_reference_view_settings_validate'),
+     );
+
+    $views_options = references_get_views_options('node');
+    if ($views_options) {
+      $view_settings = $settings['view'];
+
+      $views_options = array('' => '<' . t('none') . '>') + $views_options;
+      $default = empty($view_settings['view_name']) ? '' : $view_settings['view_name'] . ':' .$view_settings['display_name'];
+      $form['view']['view_and_display'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the nodes'),
+        '#options' => $views_options,
+        '#default_value' => $default,
+        '#description' => '<p>' . t('Choose the view and display that select the nodes that can be referenced.<br />Only views with a display of type "References" are eligible.') . '</p>' .
+          t('Note:<ul><li>This will discard the "Content types" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate nodes on node creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate nodes will be displayed.</li></ul>'),
+      );
+
+      $default = implode(', ', $view_settings['args']);
+      $form['view']['args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => $default,
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+      );
+    }
+    else {
+      $form['views']['no_view_help'] = array(
+        '#markup' => t('No eligible view was found.'),
+      );
+    }
+  }
+
   return $form;
 }
 
 /**
+ * Validate callback for the 'view settings' fielset.
+ *
+ * Puts back the various form values in the expected shape.
+ */
+function _node_reference_view_settings_validate($element, &$form_state, $form) {
+  // Split view name and display name from the 'view_and_display' value.
+  if (!empty($element['view_and_display']['#value'])) {
+    list($view, $display) = explode(':', $element['view_and_display']['#value']);
+  }
+  else {
+    $view = '';
+    $display = '';
+  }
+
+  // Explode the 'args' string into an actual array.
+  $args = array_map('trim', explode(',', $element['args']['#value']));
+
+  $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
+  form_set_value($element, $value, $form_state);
+}
+
+/**
  * Implements hook_field_validate().
  *
  * Possible error codes:
@@ -109,7 +183,10 @@ function node_reference_field_validate($entity_type, $entity, $field, $instance,
   }
   // Prevent performance hog if there are no ids to check.
   if ($ids) {
-    $refs = _node_reference_potential_references($field, '', NULL, $ids);
+    $options = array(
+      'ids' => $ids,
+    );
+    $refs = _node_reference_potential_references($field, $options);
     foreach ($items as $delta => $item) {
       if (is_array($item)) {
         if (!empty($item['nid']) && !isset($refs[$item['nid']])) {
@@ -517,13 +594,18 @@ function node_reference_autocomplete_validate($element, &$form_state, $form) {
     else {
       // No explicit nid (the submitted value was not populated by autocomplete
       // selection). Get the nid of a referencable node from the entered title.
-      $reference = _node_reference_potential_references($field, $value, 'equals', NULL, 1);
-      if ($reference) {
+      $options = array(
+        'string' => $value,
+        'match' => 'equals',
+        'limit' => 1,
+      );
+      $references = _node_reference_potential_references($field, $options);
+      if ($references) {
         // @todo The best thing would be to present the user with an
         // additional form, allowing the user to choose between valid
         // candidates with the same title. ATM, we pick the first
         // matching candidate...
-        $nid = key($reference);
+        $nid = key($references);
       }
       else {
         form_error($element, t('%name: found no valid post with that title.', array('%name' => $instance['label'])));
@@ -561,14 +643,16 @@ function _node_reference_options($field) {
 
   $options = array();
   foreach ($references as $key => $value) {
-    $options[$key] = $value['title'];
+    // We use the richer 'rendered' value rather than the raw title, but we must
+    // take care of removing tags and leaving HTML entities unencoded.
+    $options[$key] = html_entity_decode(strip_tags($value['rendered']), ENT_QUOTES);;
   }
 
   return $options;
 }
 
 /**
- * Fetch an array of all candidate referenced nodes.
+ * Retrieves an array of candidate referenceable nodes.
  *
  * This info is used in various places (allowed values, autocomplete
  * results, input validation...). Some of them only need the nids,
@@ -579,17 +663,15 @@ function _node_reference_options($field) {
  * and lets consumers use the parts they actually need.
  *
  * @param $field
- *   The field description.
- * @param $string
- *   Optional string to filter titles on (used by autocomplete).
- * @param $match
- *   Operator to match filtered name against, can be any of:
- *   'contains', 'equals', 'starts_with'
- * @param $ids
- *   Optional node ids to lookup (the $string and $match arguments will be
- *   ignored).
- * @param $limit
- *   If non-zero, limit the size of the result set.
+ *   The field definition.
+ * @param $options
+ *   An array of options to limit the scope of the returned list. The following
+ *   key/value pairs are accepted:
+ *   - string: string to filter titles on (used by autocomplete).
+ *   - match: operator to match the above string against, can be any of:
+ *     'contains', 'equals', 'starts_with'. Defaults to 'contains'.
+ *   - ids: array of specific node ids to lookup.
+ *   - limit: maximum size of the the result set. Defaults to 0 (no limit).
  *
  * @return
  *   An array of valid nodes in the form:
@@ -600,19 +682,31 @@ function _node_reference_options($field) {
  *     ),
  *     ...
  *   )
- *  @todo Check whether we still need the 'rendered' value (hook_options_list()
- *  does not need it anymore). Should probably be clearer after the 'Views'
- *  mode is ported.
  */
-function _node_reference_potential_references($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
+function _node_reference_potential_references($field, $options = array()) {
+  // Fill in default options.
+  $options += array(
+    'string' => '',
+    'match' => 'contains',
+    'ids' => array(),
+    'limit' => 0,
+  );
+
   $results = &drupal_static(__FUNCTION__, array());
 
   // Create unique id for static cache.
-  $cid = $field['field_name'] . ':' . $match . ':'
-    . ($string !== '' ? $string : implode('-', $ids))
-    . ':' . $limit;
+  $cid = $field['field_name'] . ':' . $options['match'] . ':'
+    . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids']))
+    . ':' . $options['limit'];
   if (!isset($results[$cid])) {
-    $references = _node_reference_potential_references_standard($field, $string, $match, $ids, $limit);
+    $references = FALSE;
+    if (module_exists('views') && !empty($field['settings']['view']['view_name'])) {
+      $references = _node_reference_potential_references_views($field, $options);
+    }
+
+    if ($references === FALSE) {
+      $references = _node_reference_potential_references_standard($field, $options);
+    }
 
     // Store the results.
     $results[$cid] = !empty($references) ? $references : array();
@@ -624,9 +718,20 @@ function _node_reference_potential_references($field, $string = '', $match = 'co
 /**
  * Helper function for _node_reference_potential_references().
  *
+ * Case of Views-defined referenceable nodes.
+ */
+function _node_reference_potential_references_views($field, $options) {
+  $settings = $field['settings']['view'];
+  $options['title_field'] = 'title';
+  return references_potential_references_view('node', $settings['view_name'], $settings['display_name'], $settings['args'], $options);
+}
+
+/**
+ * Helper function for _node_reference_potential_references().
+ *
  * List of referenceable nodes defined by content types.
  */
-function _node_reference_potential_references_standard($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
+function _node_reference_potential_references_standard($field, $options) {
   // Avoid useless work
   if (!count($field['settings']['referenceable_types'])) {
     return array();
@@ -643,37 +748,38 @@ function _node_reference_potential_references_standard($field, $string = '', $ma
     $query->condition('n.type', $field['settings']['referenceable_types'], 'IN');
   }
 
-  if ($string !== '') {
-    switch ($match) {
+  if ($options['string'] !== '') {
+    switch ($options['match']) {
       case 'contains':
-        $query->condition('n.title', '%' . $string . '%', 'LIKE');
+        $query->condition('n.title', '%' . $options['string'] . '%', 'LIKE');
         break;
 
       case 'starts_with':
-        $query->condition('n.title', $string . '%', 'LIKE');
+        $query->condition('n.title', $options['string'] . '%', 'LIKE');
         break;
 
       case 'equals':
       default: // no match type or incorrect match type: use "="
-        $query->condition('n.title', $string);
+        $query->condition('n.title', $options['string']);
         break;
     }
   }
-  elseif ($ids) {
-    $query->condition('n.nid', $ids, 'IN', $ids);
+
+  if ($options['ids']) {
+    $query->condition('n.nid', $options['ids'], 'IN');
+  }
+
+  if ($options['limit']) {
+    $query->range(0, $options['limit']);
   }
 
   $query
     ->orderBy($node_title_alias)
     ->orderBy($node_type_alias);
 
-  if ($limit) {
-    $query->range(0, $limit);
-  }
-
-  $result = $query->execute();
+  $result = $query->execute()->fetchAll();
   $references = array();
-  foreach ($result->fetchAll() as $node) {
+  foreach ($result as $node) {
     $references[$node->nid] = array(
       'title'    => $node->node_title,
       'rendered' => check_plain($node->node_title),
@@ -698,15 +804,23 @@ function node_reference_autocomplete_access($entity_type, $field_name) {
 function node_reference_autocomplete($entity_type, $field_name, $string = '') {
   $field = field_info_field($field_name);
 
-  // @todo broken - this is in $field['widget']['settings']['autocomplete_match'] - we'd need the $instance.
-  $match = isset($field['widget']['autocomplete_match']) ? $field['widget']['autocomplete_match'] : 'contains';
-  $matches = array();
+  $options = array(
+    'string' => $string,
+    // @todo broken - this is in $field['widget']['settings']['autocomplete_match'] - we'd need the $instance.
+    'match' => isset($field['widget']['autocomplete_match']) ? $field['widget']['autocomplete_match'] : 'contains',
+    'limit' => 10,
+  );
+  $references = _node_reference_potential_references($field, $options);
 
-  $references = _node_reference_potential_references($field, $string, $match, array(), 10);
+  $matches = array();
   foreach ($references as $id => $row) {
+    // Markup is fine in autocompletion results (might happen when rendered
+    // through Views) but we want to remove hyperlinks.
+    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
     // Add a class wrapper for a few required CSS overrides.
-    $matches[$row['title'] . " [nid:$id]"] = '<div class="reference-autocomplete">' . $row['rendered'] . '</div>';
+    $matches[$row['title'] . " [nid:$id]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
   }
+
   drupal_json_output($matches);
 }
 
diff --git references.info references.info
index c5a0dfe..b6cc1c5 100644
--- references.info
+++ references.info
@@ -6,3 +6,5 @@ dependencies[] = field
 dependencies[] = options
 files[] = views/references_handler_relationship.inc
 files[] = views/references_handler_argument.inc
+files[] = views/references_plugin_display.inc
+files[] = views/references_plugin_style.inc
diff --git references.module references.module
index 550b9a6..257e696 100644
--- references.module
+++ references.module
@@ -10,6 +10,212 @@
  */
 function references_views_api() {
   return array(
-    'api' => '3.0',
+    'api' => 3,
+    'path' => drupal_get_path('module', 'references') . '/views',
   );
 }
+
+/**
+ * Implements hook_views_plugins().
+ *
+ * Defines some plugins used by the Views modes for
+ * user_reference.
+ */
+function references_views_plugins() {
+  $plugins = array(
+    'display' => array(
+      'references' => array(
+        'title' => t('References'),
+        'admin' => t('References'),
+        'help' => 'Selects referenceable entities for a reference field (node_reference, user_reference...)',
+        'handler' => 'references_plugin_display',
+        'uses hook menu' => FALSE,
+        'use ajax' => FALSE,
+        'use pager' => FALSE,
+        'accept attachments' => FALSE,
+        // Custom property, used with views_get_applicable_views() to retrieve
+        // all views with a 'References' display.
+        'references display' => TRUE,
+      ),
+    ),
+    'style' => array(
+      'references_style' => array(
+        'title' => t('References list'),
+        'help' => '@todo Returns the view as a PHP array of names + rendered rows.',
+        'handler' => 'references_plugin_style',
+        'theme' => 'views_view_unformatted',
+        'uses row plugin' => TRUE,
+        'uses fields' => TRUE,
+        // @todo : 'Feed' displays get automatically created with the correct
+        // overriden style ('Format').
+        'type' => 'references',
+        'even empty' => TRUE,
+      ),
+    ),
+  );
+  return $plugins;
+}
+
+/**
+ * Retrieves the list of views with a 'references' display for an entity type.
+ *
+ * @param $entity_type
+ *   The entity type.
+ *
+ * @return
+ *   @todo return format is not great
+ */
+function references_get_views_options($entity_type) {
+  // Filter views that contain a 'references' display. This actually returns a
+  // list of displays (the same view appears several times).
+  $displays = views_get_applicable_views('references display');
+
+  // Filter views that list the entity type we want, and group the separate
+  // displays by view.
+  $entity_info = entity_get_info($entity_type);
+  $views = array();
+  foreach ($displays as $data) {
+    list($view, $display_id) = $data;
+    if ($view->base_table == $entity_info['base table']) {
+      if (empty($views[$view->name])) {
+        $views[$view->name] = array(
+          'view' => $view,
+          'displays' => array(),
+        );
+      }
+      $views[$view->name]['displays'][] = $display_id;
+    }
+  }
+
+  $options = array();
+  foreach ($views as $view_info) {
+    $view = $view_info['view'];
+    foreach ($view_info['displays'] as $display_id) {
+      $id = $view->name . ':' . $display_id;
+      if (count($view_info['displays']) == 1) {
+        $label = $view->name;
+      }
+      else {
+        $label = $view->name .' - ' . $view->display[$display_id]->display_title;
+      }
+      $options[$id] = $label;
+    }
+  }
+
+  return $options;
+}
+//function references_get_views($entity_type) {
+//  // Filter views that contain a 'references' display.
+//  $views = views_get_applicable_views('references display');
+//
+//  // Filter views that list the entity type we want.
+//  $entity_info = entity_get_info($entity_type);
+//  $results = array();
+//  foreach ($views as $data) {
+//    list($view, $display_id) = $data;
+//    if ($view->base_table == $entity_info['base table']) {
+//      if (!isset($results[$view->name])) {
+//        $results[$view->name] = array(
+//          'human_name' => $view->human_name,
+//          'displays' => array(),
+//        );
+//      }
+//      $results[$view->name]['displays'][$display_id] = $view->display[$display_id]->display_title;
+//    }
+//  }
+//
+//  return $results;
+//}
+
+/**
+ * Retrieves an array of candidate referenceable nodes, defined by a view.
+ *
+ * @param $entity_type
+ *   The entity type.
+ * @param $view_name
+ *   The name of the view.
+ * @param $display_name
+ *   The name of the view's display. This should be a 'References' display.
+ * @param $args
+ *   The array of arguments ("contextual filters") for the view.
+ * @param $options
+ *   Array of options to limit the scope of the returned list. This parameter
+ *   is similar to the $options parameter for
+ *   _node_reference_potential_references(). An additional key is required:
+ *   - title_field: the name of the column holding entities 'titles' within the
+ *     entity base table.
+ *
+ * @return
+ *   The list of candidate entities, in the format expected by
+ *   _node_reference_potential_references().
+ * 
+ * @see _node_reference_potential_references()
+ * @see _node_reference_potential_references_views()
+ */
+function references_potential_references_view($entity_type, $view_name, $display_name, $args, $options) {
+  $entity_info = entity_get_info($entity_type);
+
+  // Check that the view is valid and the display still exists.
+  $view = views_get_view($view_name);
+  if (!$view || $view->base_table != $entity_info['base table'] || !isset($view->display[$display_name])) {
+    return FALSE;
+  }
+
+  // Temporary backwards compatibility for fields migrated from CCK D6: accept
+  // 'default' display.
+  // @todo Test
+  // @todo Add the corresponding migration code in hook_content_migrate_instance_alter().
+  if ($display_name == 'default') {
+    $display_name = $view->add_display('references');
+    $view->display[$display_name]->set_option('style_plugin', 'references_plugin_style');
+  }
+
+  $view->set_display($display_name);
+
+  // @todo From merlinofchaos on IRC : arguments using summary view can defeat
+  // the style setting.
+  // We might also need to check if there's an argument, and set its
+  // style_plugin as well.
+
+  // Set additional options to let references_plugin_display::query() narrow
+  // the results.
+  $references_options = array(
+    'ids' => $options['ids'],
+    'title_field' => $options['title_field'],
+    'string' => $options['string'],
+    'match' => $options['string'],
+  );
+  $view->display_handler->set_option('references_options', $references_options);
+
+  // We do need the title field, so add it if not present (unlikely, but...)
+  $fields = $view->get_items('field', $display_name);
+  if (!isset($fields[$options['title_field']])) {
+    $label_options = array(
+      'label' => '',
+      'link_to_node' => 0,
+    );
+    $view->add_item($display_name, 'field', 'node', $options['title_field'], $label_options);
+  }
+
+  // Limit result set size.
+  $limit = !empty($options['limit']) ? $options['limit'] : 0;
+  $view->display_handler->set_option('pager', array('type' => 'some', 'options' => array('items_per_page' => $limit)));
+
+  // If not set, make all fields inline and define a separator.
+  $row_options = $view->display_handler->get_option('row_options');
+  if (empty($row_options['inline'])) {
+    $row_options['inline'] = drupal_map_assoc(array_keys($view->get_items('field', $display_name)));
+  }
+  if (empty($row_options['separator'])) {
+    $row_options['separator'] = '-';
+  }
+  $view->display_handler->set_option('row_options', $row_options);
+
+  // Make sure the query is not cached
+  $view->is_cacheable = FALSE;
+
+  // Get the results.
+  $results = $view->execute_display($display_name, $args);
+
+  return $results;
+}
\ No newline at end of file
diff --git user_reference/user_reference.module user_reference/user_reference.module
index 41ff2e6..3beee32 100644
--- user_reference/user_reference.module
+++ user_reference/user_reference.module
@@ -27,7 +27,15 @@ function user_reference_field_info() {
     'user_reference' => array(
       'label' => t('User reference'),
       'description' => t('This field stores the ID of a related user as an integer value.'),
-      'settings' => array('referenceable_roles' => array(), 'referenceable_status' => array()),
+      'settings' => array(
+        'referenceable_roles' => array(),
+        'referenceable_status' => array(),
+        'view' => array(
+          'view_name' => '',
+          'display_name' => '',
+          'args' => array(),
+        ),
+      ),
       'default_widget' => 'user_reference_autocomplete',
       'default_formatter' => 'user_reference_default',
       // Support hook_entity_property_info() from contrib "Entity API".
@@ -82,10 +90,77 @@ function user_reference_field_settings_form($field, $instance, $has_data) {
       : array(1),
     '#options' => array(1 => t('Active'), 0 => t('Blocked')),
   );
+
+  if (module_exists('views')) {
+    $form['view'] = array(
+       '#type' => 'fieldset',
+       '#title' => t('Views - Users that can be referenced'),
+       '#collapsible' => TRUE,
+       '#collapsed' => empty($settings['view']['view_name']),
+       '#description' => t('The list of users that can be referenced can provided by a view (Views module) using the "References" display type.'),
+       // The value of the 'view_and_display' select below will need to be split
+       // into 'view_name' and 'view_display' in the final submitted values, so
+       // we massage the data at validate time (not ideal).
+       '#element_validate' => array('_user_reference_view_settings_validate'),
+     );
+
+    $views_options = references_get_views_options('user');
+    if ($views_options) {
+      $view_settings = $settings['view'];
+
+      $views_options = array('' => '<' . t('none') . '>') + $views_options;
+      $default = empty($view_settings['view_name']) ? '' : $view_settings['view_name'] . ':' .$view_settings['display_name'];
+      $form['view']['view_and_display'] = array(
+        '#type' => 'select',
+        '#title' => t('View used to select the users'),
+        '#options' => $views_options,
+        '#default_value' => $default,
+        '#description' => '<p>' . t('Choose the view and display that select the nodes that can be referenced.<br />Only views with a display of type "References" are eligible.') . '</p>' .
+          t('Note:<ul><li>This will discard the "Referenceable Roles" and "Referenceable Status" settings above. Use the view\'s "filters" section instead.</li><li>Use the view\'s "fields" section to display additional informations about candidate users on user creation/edition form.</li><li>Use the view\'s "sort criteria" section to determine the order in which candidate users will be displayed.</li></ul>'),
+      );
+
+      $default = implode(', ', $view_settings['args']);
+      $form['view']['args'] = array(
+        '#type' => 'textfield',
+        '#title' => t('View arguments'),
+        '#default_value' => $default,
+        '#required' => FALSE,
+        '#description' => t('Provide a comma separated list of arguments to pass to the view.'),
+      );
+    }
+    else {
+      $form['views']['no_view_help'] = array(
+        '#markup' => t('No eligible view was found.'),
+      );
+    }
+  }
+
   return $form;
 }
 
 /**
+ * Validate callback for the 'view settings' fielset.
+ *
+ * Puts back the various form values in the expected shape.
+ */
+function _user_reference_view_settings_validate($element, &$form_state, $form) {
+  // Split view name and display name from the 'view_and_display' value.
+  if (!empty($element['view_and_display']['#value'])) {
+    list($view, $display) = explode(':', $element['view_and_display']['#value']);
+  }
+  else {
+    $view = '';
+    $display = '';
+  }
+
+  // Explode the 'args' string into an actual array.
+  $args = array_map('trim', explode(',', $element['args']['#value']));
+
+  $value = array('view_name' => $view, 'display_name' => $display, 'args' => $args);
+  form_set_value($element, $value, $form_state);
+}
+
+/**
  * Implements hook_field_validate().
  *
  * Possible error codes:
@@ -112,7 +187,10 @@ function user_reference_field_validate($entity_type, $entity, $field, $instance,
   }
   // Prevent performance hog if there are no ids to check.
   if ($ids) {
-    $refs = _user_reference_potential_references($field, '', NULL, $ids);
+    $options = array(
+      'ids' => $ids,
+    );
+    $refs = _user_reference_potential_references($field, $options);
     foreach ($items as $delta => $item) {
       if (is_array($item)) {
         if (!empty($item['uid']) && !isset($refs[$item['uid']])) {
@@ -353,13 +431,18 @@ function user_reference_autocomplete_validate($element, &$form_state, $form) {
     else {
       // No explicit uid (the submitted value was not populated by autocomplete
       // selection). Get the uid of a referencable user from the entered name.
-      $reference = _user_reference_potential_references($field, $value, 'equals', NULL, 1);
-      if ($reference) {
+      $options = array(
+        'string' => $value,
+        'match' => 'equals',
+        'limit' => 1,
+      );
+      $references = _user_reference_potential_references($field, $options);
+      if ($references) {
         // @todo The best thing would be to present the user with an
         // additional form, allowing the user to choose between valid
         // candidates with the same name. ATM, we pick the first
         // matching candidate...
-        $uid = key($reference);
+        $uid = key($references);
       }
       else {
         form_error($element, t('%name: found no valid user with that name.', array('%name' => $instance['label'])));
@@ -397,14 +480,16 @@ function _user_reference_options($field) {
 
   $options = array();
   foreach ($references as $key => $value) {
-    $options[$key] = $value['title'];
+    // We use the richer 'rendered' value rather than the raw title, but we must
+    // take care of removing tags and leaving HTML entities unencoded.
+    $options[$key] = html_entity_decode(strip_tags($value['rendered']), ENT_QUOTES);;
   }
 
   return $options;
 }
 
 /**
- * Fetch an array of all candidate referenced users.
+ * Retrieves an array of candidate referenceable users.
  *
  * This info is used in various places (aloowed values, autocomplete results,
  * input validation...). Some of them only need the uids, others nid + names,
@@ -413,17 +498,15 @@ function _user_reference_options($field) {
  * consumers use the parts they actually need.
  *
  * @param $field
- *   The field description.
- * @param $string
- *   Optional string to filter usernames on (used by autocomplete)
- * @param $match
- *   Operator to match filtered name against, can be any of:
- *   'contains', 'equals', 'starts_with'
- * @param $ids
- *   Optional user ids to lookup (the $string and $match arguments will be
- *   ignored).
- * @param $limit
- *   If non-zero, limit the size of the result set.
+ *   The field definition.
+ * @param $options
+ *   An array of options to limit the scope of the returned list. The following
+ *   key/value pairs are accepted:
+ *   - string: string to filter titles on (used by autocomplete).
+ *   - match: operator to match the above string against, can be any of:
+ *     'contains', 'equals', 'starts_with'. Defaults to 'contains'.
+ *   - ids: array of specific node ids to lookup.
+ *   - limit: maximum size of the the result set. Defaults to 0 (no limit).
  *
  * @return
  *   An array of valid users in the form:
@@ -435,15 +518,30 @@ function _user_reference_options($field) {
  *     ...
  *   )
  */
-function _user_reference_potential_references($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
+function _user_reference_potential_references($field, $options = array()) {
+  // Fill in default options.
+  $options += array(
+    'string' => '',
+    'match' => 'contains',
+    'ids' => array(),
+    'limit' => 0,
+  );
+
   $results = &drupal_static(__FUNCTION__, array());
 
   // Create unique id for static cache.
-  $cid = $field['field_name'] . ':' . $match . ':'
-    . ($string !== '' ? $string : implode('-', $ids))
-    . ':' . $limit;
+  $cid = $field['field_name'] . ':' . $options['match'] . ':'
+    . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids']))
+    . ':' . $options['limit'];
   if (!isset($results[$cid])) {
-    $references = _user_reference_potential_references_standard($field, $string, $match, $ids, $limit);
+    $references = FALSE;
+    if (module_exists('views') && !empty($field['settings']['view']['view_name'])) {
+      $references = _user_reference_potential_references_views($field, $options);
+    }
+
+    if ($references === FALSE) {
+      $references = _user_reference_potential_references_standard($field, $options);
+    }
 
     // Store the results.
     $results[$cid] = !empty($references) ? $references : array();
@@ -455,9 +553,20 @@ function _user_reference_potential_references($field, $string = '', $match = 'co
 /**
  * Helper function for _user_reference_potential_references().
  *
+ * Case of Views-defined referenceable users.
+ */
+function _user_reference_potential_references_views($field, $options) {
+  $settings = $field['settings']['view'];
+  $options['title_field'] = 'name';
+  return references_potential_references_view('user', $settings['view_name'], $settings['display_name'], $settings['args'], $options);
+}
+
+/**
+ * Helper function for _user_reference_potential_references().
+ *
  * List of referenceable users defined by user role and status.
  */
-function _user_reference_potential_references_standard($field, $string = '', $match = 'contains', $ids = array(), $limit = NULL) {
+function _user_reference_potential_references_standard($field, $options) {
   // Avoid useless work.
   $filter_roles = array_filter($field['settings']['referenceable_roles']);
   $filter_status = array_filter($field['settings']['referenceable_status']);
@@ -482,32 +591,32 @@ function _user_reference_potential_references_standard($field, $string = '', $ma
     $query->condition('r.rid', array_keys($filter_roles), 'IN');
   }
 
-  if ($string !== '') {
-    $args = array();
-    switch ($match) {
+  if ($options['string'] !== '') {
+    switch ($options['match']) {
       case 'contains':
-        $query->condition('u.name', '%' . $string . '%', 'LIKE');
+        $query->condition('u.name', '%' . $options['string'] . '%', 'LIKE');
         break;
 
       case 'starts_with':
-        $query->condition('u.name', $string . '%', 'LIKE');
+        $query->condition('u.name', $options['string'] . '%', 'LIKE');
         break;
 
       case 'equals':
       default: // no match type or incorrect match type: use "="
-        $query->condition('u.name', $string, '=');
+        $query->condition('u.name', $options['string'], '=');
         break;
     }
   }
-  elseif ($ids) {
-    $query->condition('u.uid', $ids, 'IN');
+
+  if ($options['ids']) {
+    $query->condition('u.uid', $options['ids'], 'IN');
   }
 
   // Explicitly exclude the anonymous user.
   $query->condition('u.uid', 0, '<>');
 
-  if ($limit) {
-    $query->range(0, $limit);
+  if ($options['limit']) {
+    $query->range(0, $options['limit']);
   }
   $query->orderBy('u.name');
 
@@ -528,13 +637,21 @@ function _user_reference_potential_references_standard($field, $string = '', $ma
 function user_reference_autocomplete($field_name, $string = '') {
   $field = field_info_field($field_name);
 
-  $match = isset($field['widget']['autocomplete_match']) ? $field['widget']['autocomplete_match'] : 'contains';
-  $matches = array();
+  $options = array(
+    'string' => $string,
+    // @todo broken - this is in $field['widget']['settings']['autocomplete_match'] - we'd need the $instance.
+    'match' => isset($field['widget']['autocomplete_match']) ? $field['widget']['autocomplete_match'] : 'contains',
+    'limit' => 10,
+  );
+  $references = _user_reference_potential_references($field, $options);
 
-  $references = _user_reference_potential_references($field, $string, $match, array(), 10);
+  $matches = array();
   foreach ($references as $id => $row) {
-    // Add a class wrapper for a few required CSS overrides.
-    $matches[$row['title'] . " [uid:$id]"] = '<div class="reference-autocomplete">' . $row['rendered'] . '</div>';
+    // Markup is fine in autocompletion results (might happen when rendered
+    // through Views) but we want to remove hyperlinks.
+    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\/a>/', '$2', $row['rendered']);
+    // Remove link tags Add a class wrapper for a few required CSS overrides.
+    $matches[$row['title'] . " [uid:$id]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
   }
   drupal_json_output($matches);
 }
diff --git views/references_plugin_display.inc views/references_plugin_display.inc
new file mode 100644
index 0000000..dd50eee
--- /dev/null
+++ views/references_plugin_display.inc
@@ -0,0 +1,88 @@
+<?php
+
+/**
+ * @file
+ * Handler for references_plugin_display.
+ */
+class references_plugin_display extends views_plugin_display {
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    // Force the style plugin to 'references_style' and the row plugin to
+    // 'fields'.
+    $options['style_plugin']['default'] = 'references_style';
+    $options['defaults']['default']['style_plugin'] = FALSE;
+    $options['defaults']['default']['style_options'] = FALSE;
+    $options['row_plugin']['default'] = 'fields';
+    $options['defaults']['default']['row_plugin'] = FALSE;
+    $options['defaults']['default']['row_options'] = FALSE;
+
+    // Set the display title to an empty string (not used in this display type).
+    $options['title']['default'] = '';
+    $options['defaults']['default']['title'] = FALSE;
+    
+    return $options;
+  }
+
+  function get_style_type() {
+    return 'references';
+  }
+
+  function execute() {
+    return $this->view->render($this->display->id);
+  }
+
+  function render() {
+    if (!empty($this->view->result) || !empty($this->view->style_plugin->definition['even empty'])) {
+      return $this->view->style_plugin->render($this->view->result);
+    }
+    return '';
+  }
+
+  function uses_exposed() {
+    return FALSE;
+  }
+
+  function query() {
+    $options = $this->get_option('references_options');
+
+    // Play nice with View UI 'preview' : if the view is not executed through
+    // _*_reference_potential_references_views(), don't alter the query.
+    if (empty($options)) {
+      return;
+    }
+
+    // Make sure the id field is included in the results, and save its alias
+    // so that references_plugin_style can retrieve it.
+    $this->id_field_alias = $this->view->query->add_field($this->view->base_table, $this->view->base_field);
+
+    // Restrict on the incoming string, or incoming ids.
+    if ($options['string'] !== '') {
+      switch ($options['match']) {
+        case 'equals':
+          $operator = '=';
+          $value = $options['string'];
+          break;
+
+        case 'starts_with':
+          $operator = 'LIKE';
+          $value = db_like($options['string']) . '%';
+          break;
+
+        case 'contains':
+        default:
+          $operator = 'LIKE';
+          $value = '%' . db_like($options['string']) . '%';
+          break;
+      }
+
+      $table_alias = $this->view->query->ensure_table($this->view->base_table);
+      $this->view->query->add_where(NULL, $table_alias . '.' . $options['title_field'], $value, $operator);
+    }
+    elseif ($options['ids']) {
+      $table_alias = $this->view->query->ensure_table($this->view->base_table);
+      $this->view->query->add_where(NULL, $table_alias . '.' . $this->view->base_field, $options['ids'], 'IN');
+    }
+  }
+}
diff --git views/references_plugin_style.inc views/references_plugin_style.inc
new file mode 100644
index 0000000..06b3ee3
--- /dev/null
+++ views/references_plugin_style.inc
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Handler for references_plugin_style.
+ */
+class references_plugin_style extends views_plugin_style {
+  function render() {
+    $options = $this->display->handler->get_option('references_options');
+
+    // Play nice with View UI 'preview' : if the view is not executed through
+    // _*_reference_potential_references_views(), just display the HTML.
+    if (empty($options)) {
+      return parent::render();
+    }
+    
+    $title_field = $options['title_field'];
+
+    // Group the rows according to the grouping field, if specified.
+    $sets = $this->render_grouping($this->view->result, $this->options['grouping']);
+
+    // Grab the alias of the 'id' field added by references_plugin_display.
+    $id_field_alias = $this->display->handler->id_field_alias;
+
+    // @todo We don't display grouping info for now. Could be useful for select
+    // widget, though.
+    $results = array();
+    $this->view->row_index = 0;
+    foreach ($sets as $title => $records) {
+      foreach ($records as $label => $values) {
+        // Render the row.
+        $rendered = $this->row_plugin->render($values);
+        // Remove linebreaks and extra spaces introduced by templates.
+        $rendered = preg_replace('/\s+/', ' ', trim($rendered));
+
+        // Collect the rendered row, and the raw title value.
+        $results[$values->{$id_field_alias}] = array(
+          'rendered' => $rendered,
+          'title' => $this->view->field[$title_field]->get_value($values),
+        );
+
+        $this->view->row_index++;
+      }
+    }
+    unset($this->view->row_index);
+
+    return $results;
+  }
+}
