Why does using '#type' => 'text_format' change the position of the field's description? I have a form with a text field which looks like this:

$form['myTextField'] = array(
    '#title' =&gt; 'Write here',
    '#type' =&gt; 'text_format',
    '#format' =&gt; 'filtered_html',
    '#description' =&gt; "Description goes here")
);


Now I would like the description to appear bewteen the title and the field, so I tried the technique described here. It works for all the other fields, but not for this one. I can make it work by changing the above code to this:

$form['myTextField'] = array(
    '#title' =&gt; 'Write here',
    '#type' =&gt; 'textarea',
    '#description' =&gt; "Description goes here")
);


The downside of this approach is that I end up with a plain old textarea instead of a text_format, which is what I need.

Any ideas as to why the description appears below the field rather than above it when I use '#type' =&gt; 'text_format' as opposed to '#type' =&gt; 'textarea'?
text_format is not a single form element that is rendered like textarea, textfield checkbox etc. Instead, it is several form elements (you get two form elements, one to select the filter, and a textarea to enter the actual text).

What you need to do is use the #after_build property to define a function that will enable you to alter the element after it has been built (the two form elements has been created). You can define custom theme function here and move data around in order to output the description and other data exactly how you want to.

Look at the FAPI documentation for more info.

Update

The #after_build on text_formats works a bit differently than expected, as it gets called twice. What you could is:

$form['text_format'] = array(
  '#type' =&gt; 'text_format',
  '#title' =&gt; t('Body'),
  '#my_description' =&gt; t('The text you enter here appears on the page.'),
  '#after_build' =&gt; array('after_build'),
);


And then

function after_build($element) {
  if ($element['#type'] == 'textarea') {
    $element['#description'] = $element['#my_description'];
  }
  return $element;
}


The idea is that you create a value for the fake description and convert it to the real description on the text area. What will happen with the normal description value is that is will be added to the filter form element only which is why your theme overrides doesn't work.