Why required form field has #required=FALSE on theme level? I have a form with managed file field. Form has single field. I have declared this field as required and indeed after submit without file I have an error: Field is required.

I wanted to add HTML5 validation to this field, but in my custom theme_file implementation $variables array has #required =&gt; FALSE for this field...

I have even red asterisk above this input field so I truly don't know what is wrong..

My custom theme_file:

function custom_file($variables) {
    if (! _custom_isMyTheme()) {
        return theme_file($variables);
    }

    $tpl = &lt;&lt;&lt;HTML
    &lt;div class="inputFile" style="width:390px; height:36px;"&gt;
        &lt;div class="inputFileContainer"&gt;
            &lt;div class="inputFileField"&gt;&lt;/div&gt;
            &lt;div class="inputFileButton"&gt;%s&lt;/div&gt;
        &lt;/div&gt;
        %s
    &lt;/div&gt;
HTML;
    dpm($variables);//devel shows #required property as FALSE
    return sprintf($tpl, t('Select'), theme_file($variables));
}
In short, the hidden input field that stores the file ID (fid) is what is required, but the displayed file upload element isn't. The actual "displayed" element is added to that form element in file_managed_file_process() in file.module. Specifically, check out line 440 of that file:

  // The file upload field itself.
  $element['upload'] = array(
    '#name' =&gt; 'files[' . implode('_', $element['#parents']) . ']',
    '#type' =&gt; 'file',
    '#title' =&gt; t('Choose a file'),
    '#title_display' =&gt; 'invisible',
    '#size' =&gt; $element['#size'],
    '#theme_wrappers' =&gt; array(),
    '#weight' =&gt; -10,
  );


This has no #required property, and so therefore defaults to FALSE. If you dpm() your element earlier in the process (before it's expanded to include more hidden elements and attach the necessary javascript and CSS to be a full-fledged "managed file" element) you'll see your #required =&gt; TRUE.

I would add an additional function to the #process property of your form element, which will run after file_managed_file_process(). In it, you can check if the original element had #required =&gt; TRUE and then also set that on the $element['upload'] item. I haven't tried it, but I think that would get you what you want.

Edit: It would be wiser to do this in #after_build and not just append to #process. Here's an example:

&lt;?php

function my_form_builder($form, &amp;$form_state) {
  $form['file'] = array(
    '#type' =&gt; 'managed_file',
    '#title' =&gt; 'Upload a File',
    '#required' =&gt; TRUE,
    '#after_build' =&gt; array('my_file_element_after_build')
  );

  return $form;
}

function my_file_element_after_build($element, &amp;$form_state) {
  // Set the 'file' element to have the same #required property as its original form element.
  $element['upload']['#required'] = $element['#required'];
  return $element;
}

?&gt;