How do I change a widget's markup? I need to create another widget which acts exactly like a text field, but contains a button and link next to the element. What's the best way to accomplish this?

I thought of:


Copying the Text Module (with the Field Module) and looking for the HTML.
Downloading the Autocomplete module and editing its markup.


I haven't really seen where the HTML for widgets is. Is this even possible?
In Drupal 7, to implement a new widget, you need to implement the following hooks:


hook_field_widget_info()
hook_field_widget_form()
hook_field_widget_error()


hook_field_widget_info() returns information about the type of widget implemented, such as the fields supported from the widget and for which the widget can be used. An example of implementation is image_field_widget_info().

function image_field_widget_info() {
  return array(
    'image_image' =&gt; array(
      'label' =&gt; t('Image'), 
      'field types' =&gt; array('image'), 
      'settings' =&gt; array(
        'progress_indicator' =&gt; 'throbber', 
        'preview_image_style' =&gt; 'thumbnail',
      ), 
      'behaviors' =&gt; array(
        'multiple values' =&gt; FIELD_BEHAVIOR_CUSTOM, 
        'default value' =&gt; FIELD_BEHAVIOR_NONE,
      ),
    ),
  );
}


hook_field_widget_form() is the hook that returns the form field(s) necessary to get values for the field, which is what in Drupal 7 is called widget.
The reason you don't find any HTML in a module implementing a widget is that a widget is made of one or more form fields, which are defined using a form API array. If you look at file_field_widget_form(), you will notice that it uses a managed_file form field, but it also uses a theme function, and a form field process function.

  $element_info = element_info('managed_file');
  $element += array(
    '#type' =&gt; 'managed_file', 
    '#upload_location' =&gt; file_field_widget_uri($field, $instance), 
    '#upload_validators' =&gt; file_field_widget_upload_validators($field, $instance), 
    '#value_callback' =&gt; 'file_field_widget_value', 
    '#process' =&gt; array_merge($element_info['#process'], array('file_field_widget_process')), 
    '#progress_indicator' =&gt; $instance['widget']['settings']['progress_indicator'],
    // Allows this field to return an array instead of a single value. 
    '#extended' =&gt; TRUE,
  );




  if ($field['cardinality'] == 1) {
    // Set the default value.
    $element['#default_value'] = !empty($items) ? $items[0] : $defaults;
    // If there's only one field, return it as delta 0.
    if (empty($element['#default_value']['fid'])) {
      $element['#description'] = theme('file_upload_help', array('description' =&gt; $element['#description'], 'upload_validators' =&gt; $element['#upload_validators']));
    }
    $elements = array($element);
  }


As I said, a widget is used to get the value associated with a field; when you need to show the value associated with a field, you need to create a formatter through hook_field_formatter_view(). See Field Formatter API for more information.