How to add image field in a custom module form? In our custom module, mymodule we have a form MyModuleForm where we want to allow for an image to be uploaded or chosen from already uploaded images. Below is the MyModuleForm.php file, but cannot figure out why we are not able to upload the Image and save it. There is a menu link where the module's form is and when we navigate to the page we see a blank page with no field or widget to set the image. 

Goal 


To be able to make the Image Browser widget display so that we can use an existing image or upload one. 
Store the image using MyModuleForm from the custom module.
We should be able to change the image as needed and save the configuration. 
Set file status to permanent.
Add to file usage calculation. 


How do we add an Image field on our MyModuleForm so that we can either use an existing image or upload a new one?

Here is what we tried but didn't work

MyModuleForm.php

class MyModuleForm extends ConfigFormBase {
  protected function getEditableConfigNames() {
    return [
      'mymodule.settings'
    ];
  }

  public function getFormId() {
    return 'mymodule_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this-&gt;config('mymodule.settings');
    $form['my_file'] = [
      '#type' =&gt; 'managed_file',
      '#title' =&gt; 'my file',
      '#name' =&gt; 'my_custom_file',
      '#description' =&gt; $this-&gt;t('my file description'),
      '#default_value' =&gt; $config-&gt;get('my_file'),
      '#upload_location' =&gt; 'public://'
    ];

    return parent::buildForm($form, $form_state);
  }

  public function validateForm(array &amp;$form, FormStateInterface $form_state) {
    parent::validateForm($form, $form_state);
  }

  public function submitForm(array &amp;$form, FormStateInterface $form_state) {
    // Check if image is uploaded.
    if(isset($form_state['default_press_release_image'])) {
      // Set file status to permanent.
      $image = $form_state-&gt;getValue('my_file');
      $file = File::load($image[0]);
      $file-&gt;setPermanent();
      $file-&gt;save();
      // Add to file usage calculation.
      \Drupal::service('file.usage')-&gt;add;
    }

    $this-&gt;config('ns_default_images.settings')
      -&gt;set('default_press_release_image', $form_state-&gt;getValue('default_press_release_image'))
      -&gt;save();

    parent::submitForm($form, $form_state);
  }
}
The default_value attribute accept an array in case of managed_file:

  $form['my_file'] = [
      '#type' =&gt; 'managed_file',
      '#title' =&gt; 'my file',
      '#name' =&gt; 'my_custom_file',
      '#description' =&gt; $this-&gt;t('my file description'),
      '#default_value' =&gt; [$config-&gt;get('my_file')],
      '#upload_location' =&gt; 'public://'
    ];


In The submit function you are using a field name different from the declared one in the buildForm().

The value of a managed_file should be an array even when the field is not multiple:

$form_state-&gt;getValue('default_press_release_image')[0];