diff --git a/js/entity_browser.common.js b/js/entity_browser.common.js
index 896f9cd..3ac1ebb 100644
--- a/js/entity_browser.common.js
+++ b/js/entity_browser.common.js
@@ -22,7 +22,7 @@
    */
   Drupal.entityBrowser.selectionCompleted = function (event, uuid, entities) {
     var added_entities_array = $.map(entities, function (item) {
-      return item[0];
+      return item[2] + ':' + item[0];
     });
     // @todo Use uuid here. But for this to work we need to move eb uuid
     // generation from display to eb directly. When we do this, we can change
diff --git a/modules/entity_form/entity_browser_entity_form.module b/modules/entity_form/entity_browser_entity_form.module
index 35805dc..4243ade 100644
--- a/modules/entity_form/entity_browser_entity_form.module
+++ b/modules/entity_form/entity_browser_entity_form.module
@@ -7,70 +7,51 @@
  * Provides integration with the Inline entity form module.
  */
 
-use Drupal\entity_browser\Events\RegisterJSCallbacks;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\WidgetInterface;
 use Drupal\Core\Url;
-use Drupal\entity_browser\Events\Events;
 use Drupal\Component\Utility\NestedArray;
 
 /**
  * Implements hook_inline_entity_form_reference_form_alter().
  */
 function entity_browser_entity_form_inline_entity_form_reference_form_alter(&$reference_form, FormStateInterface &$form_state) {
-  $entity_type_manager = \Drupal::entityTypeManager();
-  \Drupal::service('event_dispatcher')
-    ->addListener(
-      Events::REGISTER_JS_CALLBACKS,
-      'entity_browser_entity_form_reference_register_js'
-    );
-
   /** @var \Drupal\field\FieldConfigInterface $instance */
-  $instance = $form_state->get(['inline_entity_form', $reference_form['#ief_id'], 'instance']);
+  $instance = $form_state->get([
+    'inline_entity_form',
+    $reference_form['#ief_id'],
+    'instance',
+  ]);
 
   /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display */
   $entity_form_id = $instance->getTargetEntityTypeId() . '.' . $instance->getTargetBundle() . '.default';
   // TODO - 'default' might become configurable or something else in the future.
   // See https://www.drupal.org/node/2510274
-  $form_display = $entity_type_manager->getStorage('entity_form_display')->load($entity_form_id);
+  $form_display = \Drupal::entityTypeManager()->getStorage('entity_form_display')->load($entity_form_id);
 
   $widget = $form_display->getRenderer($instance->getName());
 
-  if (!empty($widget->getThirdPartySetting('entity_browser_entity_form', 'entity_browser_id')) &&
-    $widget->getThirdPartySetting('entity_browser_entity_form', 'entity_browser_id') !== '_none') {
-    $entity_browser_id = $widget->getThirdPartySetting('entity_browser_entity_form', 'entity_browser_id');
-    if ($browser = $entity_type_manager->getStorage('entity_browser')->load($entity_browser_id)) {
-      /** @var \Drupal\entity_browser\EntityBrowserInterface $browser */
-      $display = $browser->getDisplay();
-
-      $reference_form['entity_id'] = [
-        '#type' => 'hidden',
-        '#attributes' => [
-          'class' => ['ief-entity-browser-value'],
-        ],
-      ];
-      $reference_form['entity_browser'] = $display->displayEntityBrowser($form_state);
-      $reference_form['#attached']['library'][] = 'entity_browser_entity_form/ief_autocomplete';
-      $reference_form['actions']['ief_reference_save']['#ajax']['event'] = 'entities-selected';
-
-      // Add custom validation and submit callbacks as we need to handle
-      // multi-value cases.
-      $reference_form['#element_validate'][0] = 'entity_browser_entity_form_reference_form_validate';
-      $reference_form['#ief_element_submit'][0] = 'entity_browser_entity_form_reference_form_submit';
+  if (empty($widget->getThirdPartySetting('entity_browser_entity_form', 'entity_browser_id'))) {
+    return;
+  }
 
-      // Add cardinality for this widget so that we can handle it later.
-      $reference_form['#attached']['drupalSettings']['entity_browser'][$display->getUuid()]['cardinality'] = $instance->getFieldStorageDefinition()->getCardinality();
-    }
+  if ($widget->getThirdPartySetting('entity_browser_entity_form', 'entity_browser_id') === '_none') {
+    return;
   }
-}
 
-/**
- * Registers JS callback that gets entities from entity browser and updates
- * form values accordingly.
- */
-function entity_browser_entity_form_reference_register_js(RegisterJSCallbacks $event) {
-  $event->registerCallback('Drupal.entityBrowser.selectionCompleted');
+  unset($reference_form['entity_id']);
+  $reference_form['entity_browser'] = [
+    '#type' => 'entity_browser',
+    '#entity_browser' => $widget->getThirdPartySetting('entity_browser_entity_form', 'entity_browser_id'),
+  ];
+  $reference_form['#attached']['library'][] = 'entity_browser_entity_form/ief_autocomplete';
+  $reference_form['actions']['ief_reference_save']['#ajax']['event'] = 'entities-selected';
+
+  // Add custom validation and submit callbacks as we need to handle
+  // multi-value cases.
+  $reference_form['#element_validate'][0] = 'entity_browser_entity_form_reference_form_validate';
+  $reference_form['#ief_element_submit'][0] = 'entity_browser_entity_form_reference_form_submit';
 }
 
 /**
@@ -78,16 +59,16 @@ function entity_browser_entity_form_reference_register_js(RegisterJSCallbacks $e
  *
  * TODO see if we can get away without overriding entire IEF function.
  *
- * @see inline_entity_form_reference_form_validate()
- *
- * @param $reference_form
+ * @param array $reference_form
  *   The reference entity form.
- * @param $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The form state of the parent form.
+ *
+ * @see inline_entity_form_reference_form_validate()
  */
-function entity_browser_entity_form_reference_form_validate(&$reference_form, FormStateInterface $form_state) {
+function entity_browser_entity_form_reference_form_validate(array &$reference_form, FormStateInterface $form_state) {
   $form_values = NestedArray::getValue($form_state->getValues(), $reference_form['#parents']);
-  if (empty($form_values['entity_id'])) {
+  if (empty($form_values['entity_browser']['entity_ids'])) {
     // The entity_id element is required, the value is empty only if
     // the form was cancelled.
     return;
@@ -95,7 +76,14 @@ function entity_browser_entity_form_reference_form_validate(&$reference_form, Fo
   $ief_id = $reference_form['#ief_id'];
   $labels = $reference_form['#ief_labels'];
   $storage = \Drupal::entityTypeManager()->getStorage($reference_form['#entity_type']);
-  $attach_entities = $storage->loadMultiple(explode(' ', $form_values['entity_id']));
+  $attach_entities = $storage->loadMultiple(
+    array_map(
+      function ($item) {
+        return explode(':', $item)[1];
+      },
+      explode(' ', $form_values['entity_browser']['entity_ids'])
+    )
+  );
 
   // Check if the entity is already referenced by the field.
   if (!empty($attach_entities)) {
@@ -116,18 +104,25 @@ function entity_browser_entity_form_reference_form_validate(&$reference_form, Fo
  *
  * TODO see if we can get away without overriding entire IEF function.
  *
- * @see inline_entity_form_reference_form_submit()
- *
- * @param $reference_form
+ * @param array $reference_form
  *   The reference entity form.
- * @param $form_state
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
  *   The form state of the parent form.
+ *
+ * @see inline_entity_form_reference_form_submit()
  */
 function entity_browser_entity_form_reference_form_submit($reference_form, FormStateInterface $form_state) {
   $ief_id = $reference_form['#ief_id'];
   $form_values = NestedArray::getValue($form_state->getValues(), $reference_form['#parents']);
   $storage = \Drupal::entityTypeManager()->getStorage($reference_form['#entity_type']);
-  $attach_entities = $storage->loadMultiple(explode(' ', $form_values['entity_id']));
+  $attach_entities = $storage->loadMultiple(
+    array_map(
+      function ($item) {
+        return explode(':', $item)[1];
+      },
+      explode(' ', $form_values['entity_browser']['entity_ids'])
+    )
+  );
   $entities =& $form_state->get(['inline_entity_form', $ief_id, 'entities']);
 
   // Determine the correct weight of the new element.
@@ -139,7 +134,7 @@ function entity_browser_entity_form_reference_form_submit($reference_form, FormS
   foreach ($attach_entities as $attach_entity) {
     $entities[] = array(
       'entity' => $attach_entity,
-      '_weight' => $weight,
+      'weight' => $weight,
       'form' => NULL,
       'needs_save' => FALSE,
     );
@@ -147,12 +142,12 @@ function entity_browser_entity_form_reference_form_submit($reference_form, FormS
   }
   $form_state->set(['inline_entity_form', $ief_id, 'entities'], $entities);
 
-  // In some rare cases entity_id keeps values of selected entities which then
+  // In some rare cases entity_ids keeps values of selected entities which then
   // causes problems in subsequent selections. Let's make sure it is empty and
   // ready for next usage of entity browser.
-  $form_state->setValueForElement($reference_form['entity_id'], '');
+  $form_state->setValueForElement($reference_form['entity_browser']['entity_ids'], '');
   $input = &$form_state->getUserInput();
-  NestedArray::unsetValue($input, array_merge($reference_form['#parents'], ['entity_id']));
+  NestedArray::unsetValue($input, array_merge($reference_form['#parents'], ['entity_browser', 'entity_ids']));
 }
 
 /**
diff --git a/src/DisplayBase.php b/src/DisplayBase.php
index 3a4a5b2..60531fd 100644
--- a/src/DisplayBase.php
+++ b/src/DisplayBase.php
@@ -156,14 +156,14 @@ abstract class DisplayBase extends PluginBase implements DisplayInterface, Conta
   /**
    * {@inheritdoc}
    */
-  public function displayEntityBrowser(FormStateInterface $form_state, array $validators = [], array $entities = []) {
+  public function displayEntityBrowser(FormStateInterface $form_state, array $element, array &$complete_form, array $validators = [], array $entities = []) {
     // Store our validators and currently selected entities so that after being
     // rendered they can be accessed.
     $this->selectionStorage->setWithExpire(
       $this->getUuid(),
       [
         'entities' => $entities,
-        'validators' => $validators
+        'validators' => $validators,
       ],
       Settings::get('entity_browser_expire', 21600)
     );
diff --git a/src/DisplayInterface.php b/src/DisplayInterface.php
index fe0515a..4427075 100644
--- a/src/DisplayInterface.php
+++ b/src/DisplayInterface.php
@@ -36,15 +36,23 @@ interface DisplayInterface extends PluginInspectionInterface, ConfigurablePlugin
    *
    * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The form state object.
+   * @param array $element
+   *   A form element array containing basic properties for the entity browser
+   *   element:
+   *   - #eb_parents: The 'parents' space for the field in the form.
+   * @param array $complete_form
+   *   The form structure where entity browser is being attached to.
    * @param array $validators
-   *   (optional) An array of WidgetValidator plugin IDs.
+   *   (optional) An array of WidgetValidator plugins. Array keys are plugin IDs
+   *   and array values are plugin configuration values.
    * @param \Drupal\Core\Entity\EntityInterface[] $entities
-   *   (optional) Existing selection that should be passed to the entity browser.
+   *   (optional) Existing selection that should be passed to the entity
+   *   browser.
    *
    * @return array
    *   An array suitable for drupal_render().
    */
-  public function displayEntityBrowser(FormStateInterface $form_state, array $validators = [], array $entities = []);
+  public function displayEntityBrowser(FormStateInterface $form_state, array $element, array &$complete_form, array $validators = [], array $entities = []);
 
   /**
    * Indicates completed selection.
@@ -54,6 +62,7 @@ interface DisplayInterface extends PluginInspectionInterface, ConfigurablePlugin
    * the initiating code.
    *
    * @param \Drupal\Core\Entity\EntityInterface[] $entities
+   *   Array of selected entities.
    */
   public function selectionCompleted(array $entities);
 
diff --git a/src/Element/EntityBrowserElement.php b/src/Element/EntityBrowserElement.php
new file mode 100644
index 0000000..343a393
--- /dev/null
+++ b/src/Element/EntityBrowserElement.php
@@ -0,0 +1,131 @@
+<?php
+
+namespace Drupal\entity_browser\Element;
+
+use Drupal\Component\Utility\Html;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element\FormElement;
+use Drupal\entity_browser\Entity\EntityBrowser;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides an Entity Browser form element.
+ *
+ * Properties:
+ * - #entity_browser: Entity browser or ID of the Entity browser to be used.
+ * - #cardinality: (optional) Maximum number of items that are expected from
+ *     the entity browser. Unlimited by default.
+ * - #default_value: (optional) Array of entities that Entity browser should be
+ *     initialized with.
+ * - #entity_browser_validators: (optional) Array of validators that are to be
+ *     passed to the entity browser. Array keys are plugin IDs and array values
+ *     are plugin configuration values. Cardinality validator will be set
+ *     automatically.
+ *
+ * Return value will be an array of selected entities, which will appear under
+ * 'entities' key on the root level of the element's values in the form state.
+ *
+ * @FormElement("entity_browser")
+ */
+class EntityBrowserElement extends FormElement {
+
+  /**
+   * Indicating an entity browser can return an unlimited number of values.
+   */
+  const CARDINALITY_UNLIMITED = -1;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getInfo() {
+    $class = get_class($this);
+    return [
+      '#input' => TRUE,
+      '#tree' => TRUE,
+      '#cardinality' => $this::CARDINALITY_UNLIMITED,
+      '#process' => [[$class, 'processEntityBrowser']],
+      '#default_value' => [],
+      '#entity_browser_validators' => [],
+      '#attached' => ['library' => ['entity_browser/common']],
+    ];
+  }
+
+  /**
+   * Render API callback: Processes the entity browser element.
+   */
+  public static function processEntityBrowser(&$element, FormStateInterface $form_state, &$complete_form) {
+    /** @var \Drupal\entity_browser\EntityBrowserInterface $entity_browser */
+    if (is_string($element['#entity_browser'])) {
+      $entity_browser = EntityBrowser::load($element['#entity_browser']);
+    }
+    else {
+      $entity_browser = $element['#entity_browser'];
+    }
+
+    $default_value = implode(' ', array_map(
+      function (EntityInterface $item) {
+        return $item->getEntityTypeId() . ':' . $item->id();
+      },
+      $element['#default_value']
+    ));
+    $validators = array_merge(
+      $element['#entity_browser_validators'],
+      ['cardinality' => ['cardinality' => $element['#cardinality']]]
+    );
+
+    $display = $entity_browser->getDisplay();
+    $display->setUuid(sha1(implode('-', array_merge([$complete_form['#build_id']], $element['#parents']))));
+    $element['entity_browser'] = [
+      '#eb_parents' => array_merge($element['#parents'], ['entity_browser']),
+    ];
+    $element['entity_browser'] = $display->displayEntityBrowser(
+      $form_state,
+      $element['entity_browser'],
+      $complete_form,
+      $validators,
+      $element['#default_value']
+    );
+
+    $hidden_id = Html::getUniqueId($element['#id'] . '-target');
+    $element['entity_ids'] = [
+      '#type' => 'hidden',
+      '#id' => $hidden_id,
+      // We need to repeat ID here as it is otherwise skipped when rendering.
+      '#attributes' => ['id' => $hidden_id, 'class' => ['ed-target']],
+      '#default_value' => $default_value,
+    ];
+
+    $element['#attached']['drupalSettings']['entity_browser'] = [
+      $entity_browser->getDisplay()->getUuid() => [
+        'cardinality' => $element['#cardinality'],
+        'selector' => '#' . $hidden_id,
+      ],
+    ];
+
+    return $element;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
+    if ($input === FALSE) {
+      return $element['#default_value'] ?: [];
+    }
+
+    if ($input['entity_ids']) {
+      return [
+        'entities' => array_map(
+          function ($item) {
+            list($entity_type, $entity_id) = explode(':', $item);
+            return \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
+          },
+          explode(' ', $input['entity_ids'])
+        ),
+      ];
+    }
+
+    return ['entities' => []];
+  }
+
+}
diff --git a/src/Plugin/EntityBrowser/Display/IFrame.php b/src/Plugin/EntityBrowser/Display/IFrame.php
index 4aef4fe..8b1956d 100644
--- a/src/Plugin/EntityBrowser/Display/IFrame.php
+++ b/src/Plugin/EntityBrowser/Display/IFrame.php
@@ -115,7 +115,7 @@ class IFrame extends DisplayBase implements DisplayRouterInterface {
   /**
    * {@inheritdoc}
    */
-  public function displayEntityBrowser(FormStateInterface $form_state, array $validators = [], array $entities = []) {
+  public function displayEntityBrowser(FormStateInterface $form_state, array $element, array &$complete_form, array $validators = [], array $entities = []) {
     parent::displayEntityBrowser($form_state, $validators, $entities);
     /** @var \Drupal\entity_browser\Events\RegisterJSCallbacks $event */
     $js_event_object = new RegisterJSCallbacks($this->configuration['entity_browser_id'], $this->getUuid());
diff --git a/src/Plugin/EntityBrowser/Display/Modal.php b/src/Plugin/EntityBrowser/Display/Modal.php
index 62e6c9b..14b0603 100644
--- a/src/Plugin/EntityBrowser/Display/Modal.php
+++ b/src/Plugin/EntityBrowser/Display/Modal.php
@@ -70,16 +70,16 @@ class Modal extends DisplayBase implements DisplayRouterInterface {
    *   The plugin implementation definition.
    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
    *   Event dispatcher service.
-   * @param \Drupal\Component\Uuid\UuidInterface
+   * @param \Drupal\Component\Uuid\UuidInterface $uuid
    *   UUID generator interface.
    * @param \Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface $selection_storage
    *   The selection storage.
    * @param \Drupal\Core\Routing\RouteMatchInterface $current_route_match
    *   The currently active route match object.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   Current request.
    * @param \Drupal\Core\Path\CurrentPathStack $current_path
    *   The current path.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   Current request.
    */
   public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher, UuidInterface $uuid, KeyValueStoreExpirableInterface $selection_storage, RouteMatchInterface $current_route_match, CurrentPathStack $current_path, Request $request) {
     parent::__construct($configuration, $plugin_id, $plugin_definition, $event_dispatcher, $uuid, $selection_storage);
@@ -119,7 +119,7 @@ class Modal extends DisplayBase implements DisplayRouterInterface {
   /**
    * {@inheritdoc}
    */
-  public function displayEntityBrowser(FormStateInterface $form_state, array $validators = [], array $entities = []) {
+  public function displayEntityBrowser(FormStateInterface $form_state, array $element, array &$complete_form, array $validators = [], array $entities = []) {
     parent::displayEntityBrowser($form_state, $validators, $entities);
     $js_event_object = new RegisterJSCallbacks($this->configuration['entity_browser_id'], $this->getUuid());
     $js_event_object->registerCallback('Drupal.entityBrowser.selectionCompleted');
@@ -151,7 +151,7 @@ class Modal extends DisplayBase implements DisplayRouterInterface {
         '#value' => $this->configuration['link_text'],
         '#limit_validation_errors' => [],
         '#submit' => [],
-        '#name' => Html::getId('op_' . $this->configuration['entity_browser_id'] . '_' . $this->getUuid()),
+        '#name' => implode('_', $element['#eb_parents']),
         '#ajax' => [
           'callback' => [$this, 'openModal'],
           'event' => 'click',
@@ -340,7 +340,7 @@ class Modal extends DisplayBase implements DisplayRouterInterface {
   }
 
   /**
-   * @inheritDoc
+   * {@inheritdoc}
    */
   public function __sleep() {
     return ['configuration'];
diff --git a/src/Plugin/EntityBrowser/Display/Standalone.php b/src/Plugin/EntityBrowser/Display/Standalone.php
index a5216b8..087af0a 100644
--- a/src/Plugin/EntityBrowser/Display/Standalone.php
+++ b/src/Plugin/EntityBrowser/Display/Standalone.php
@@ -45,7 +45,7 @@ class Standalone extends DisplayBase implements DisplayRouterInterface {
   /**
    * {@inheritdoc}
    */
-  public function displayEntityBrowser(FormStateInterface $form_state, array $validators = [], array $entities = []) {
+  public function displayEntityBrowser(FormStateInterface $form_state, array $element, array &$complete_form, array $validators = [], array $entities = []) {
     parent::displayEntityBrowser($form_state, $validators, $entities);
     // @TODO Implement it.
   }
diff --git a/src/Plugin/Field/FieldWidget/EntityReference.php b/src/Plugin/Field/FieldWidget/EntityReference.php
index b7c11ae..02b7eeb 100644
--- a/src/Plugin/Field/FieldWidget/EntityReference.php
+++ b/src/Plugin/Field/FieldWidget/EntityReference.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\entity_browser\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Entity\EntityInterface;
 use Symfony\Component\Validator\ConstraintViolationInterface;
 use Drupal\Component\Utility\Html;
 use Drupal\Component\Utility\NestedArray;
@@ -318,6 +319,7 @@ class EntityReference extends WidgetBase implements ContainerFactoryPluginInterf
 
       if (isset($parents) && $value = $form_state->getValue($parents)) {
         $ids = explode(' ', $value);
+        $ids = array_map(function ($item) {return explode(':', $item)[1];}, $ids);
         $entities = $entity_storage->loadMultiple($ids);
       }
     }
@@ -351,20 +353,23 @@ class EntityReference extends WidgetBase implements ContainerFactoryPluginInterf
 
     $hidden_id = Html::getUniqueId('edit-' . $this->fieldDefinition->getName() . '-target-id');
     $details_id = Html::getUniqueId('edit-' . $this->fieldDefinition->getName());
-    /** @var \Drupal\entity_browser\EntityBrowserInterface $entity_browser */
-    $entity_browser = $this->entityTypeManager->getStorage('entity_browser')->load($this->getSetting('entity_browser'));
 
     $element += [
       '#id' => $details_id,
       '#type' => 'details',
-      '#open' => !empty($ids) || $this->getSetting('open'),
+      '#open' => !empty($entities) || $this->getSetting('open'),
       '#required' => $this->fieldDefinition->isRequired(),
+      // We are not using Entity browser's hidden element since we maintain
+      // selected entities in it during entire process.
       'target_id' => [
         '#type' => 'hidden',
         '#id' => $hidden_id,
         // We need to repeat ID here as it is otherwise skipped when rendering.
         '#attributes' => ['id' => $hidden_id],
-        '#default_value' => $ids,
+        '#default_value' => array_map(
+          function (EntityInterface $item) { return $item->getEntityTypeId() . ':' . $item->id(); },
+          $entities
+        ),
         // #ajax is officially not supported for hidden elements but if we
         // specify event manually it works.
         '#ajax' => [
@@ -377,24 +382,19 @@ class EntityReference extends WidgetBase implements ContainerFactoryPluginInterf
 
     $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality();
     if ($cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED || count($ids) < $cardinality) {
-      $entity_browser_uuid = sha1(implode('-', array_merge($form['#parents'], [$this->fieldDefinition->getName(), $delta])));
-      $entity_browser_display = $entity_browser->getDisplay();
-      $entity_browser_display->setUuid($entity_browser_uuid);
-
-      // Gather and set validators.
-      $validators = [
-        'entity_type' => ['type' => $entity_type],
-        'cardinality' => ['cardinality' => $cardinality],
+      $element['entity_browser'] = [
+        '#type' => 'entity_browser',
+        '#entity_browser' => $this->getSetting('entity_browser'),
+        '#cardinality' => $cardinality,
+        '#entity_browser_validators' => ['entity_type' => ['type' => $entity_type]],
+        '#custom_hidden_id' => $hidden_id,
+        '#process' => [
+          ['\Drupal\entity_browser\Element\EntityBrowserElement', 'processEntityBrowser'],
+          [get_called_class(), 'processEntityBrowser'],
+        ],
       ];
 
-      $element['entity_browser'] = $entity_browser_display->displayEntityBrowser($form_state, $validators, []);
       $element['#attached']['library'][] = 'entity_browser/entity_reference';
-      $element['#attached']['drupalSettings']['entity_browser'] = [
-        $entity_browser->getDisplay()->getUuid() => [
-          'cardinality' => $cardinality,
-          'selector' => '#' . $element['target_id']['#attributes']['id'],
-        ],
-      ];
     }
 
     $field_parents = $element['#field_parents'];
@@ -405,13 +405,22 @@ class EntityReference extends WidgetBase implements ContainerFactoryPluginInterf
   }
 
   /**
+   * Render API callback: Processes the entity browser element.
+   */
+  public static function processEntityBrowser(&$element, FormStateInterface $form_state, &$complete_form) {
+    $uuid = key($element['#attached']['drupalSettings']['entity_browser']);
+    $element['#attached']['drupalSettings']['entity_browser'][$uuid]['selector'] = '#' . $element['#custom_hidden_id'];
+    return $element;
+  }
+
+  /**
    * {@inheritdoc}
    */
   public function massageFormValues(array $values, array $form, FormStateInterface $form_state) {
-    $ids = empty($values['target_id']) ? [] : explode(' ', trim($values['target_id']));
+    $entities = empty($values['target_id']) ? [] : explode(' ', trim($values['target_id']));
     $return = [];
-    foreach ($ids as $id) {
-      $return[]['target_id'] = $id;
+    foreach ($entities as $entity) {
+      $return[]['target_id'] = explode(':', $entity)[1];
     }
 
     return $return;
@@ -511,7 +520,7 @@ class EntityReference extends WidgetBase implements ContainerFactoryPluginInterf
             '#theme_wrappers' => ['container'],
             '#attributes' => [
               'class' => ['item-container', Html::getClass($field_widget_display->getPluginId())],
-              'data-entity-id' => $entity->id(),
+              'data-entity-id' => $entity->getEntityTypeId() . ':' . $entity->id(),
             ],
             'display' => $display,
             'remove_button' => [
@@ -524,7 +533,7 @@ class EntityReference extends WidgetBase implements ContainerFactoryPluginInterf
               '#submit' => [[get_class($this), 'removeItemSubmit']],
               '#name' => $this->fieldDefinition->getName() . '_remove_' . $entity->id(),
               '#limit_validation_errors' => [array_merge($field_parents, [$this->fieldDefinition->getName()])],
-              '#attributes' => ['data-entity-id' => $entity->id()],
+              '#attributes' => ['data-entity-id' => $entity->getEntityTypeId() . ':' . $entity->id()],
               '#access' => (bool) $this->getSetting('field_widget_remove'),
             ],
             'edit_button' => [
diff --git a/src/Tests/FormElementTest.php b/src/Tests/FormElementTest.php
new file mode 100644
index 0000000..7c9d6ea
--- /dev/null
+++ b/src/Tests/FormElementTest.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Drupal\entity_browser\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests the entity browser form element.
+ *
+ * @group entity_browser
+ */
+class FormElementTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['entity_browser_test', 'node', 'views'];
+
+  /**
+   * Test nodes.
+   *
+   * @var \Drupal\node\NodeInterface[]
+   */
+  protected $nodes;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->container
+      ->get('entity_type.manager')
+      ->getStorage('node_type')
+      ->create([
+        'type' => 'page',
+        'name' => 'page',
+      ])->save();
+
+    $this->nodes[] = $this->drupalCreateNode();
+    $this->nodes[] = $this->drupalCreateNode();
+  }
+
+  /**
+   * Tests the Entity browser form element.
+   */
+  public function testFormElement() {
+    $this->drupalGet('/test-element');
+    $this->assertLink('Select entities', 0, 'Trigger link found.');
+    $this->assertFieldByXPath("//input[@type='hidden' and @id='edit-fancy-entity-browser-target']", '', "Entity browser's hidden element found.");
+
+    $edit = [
+      'fancy_entity_browser[entity_ids]' => $this->nodes[0]->getEntityTypeId() . ':' . $this->nodes[0]->id() . ' ' . $this->nodes[1]->getEntityTypeId() . ':' . $this->nodes[1]->id(),
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Submit');
+    $expected = 'Selected entities: ' . $this->nodes[0]->label() . ', ' . $this->nodes[1]->label();
+    $this->assertText($expected, 'Selected entities detected.');
+
+    $default_entity = $this->nodes[0]->getEntityTypeId() . ':' . $this->nodes[0]->id();
+    $this->drupalGet('/test-element', ['query' => ['default_entity' => $default_entity]]);
+    $this->assertLink('Select entities', 0, 'Trigger link found.');
+    $this->assertFieldByXPath("//input[@type='hidden' and @id='edit-fancy-entity-browser-target']", $default_entity, "Entity browser's hidden element found.");
+
+    $edit = [
+      'fancy_entity_browser[entity_ids]' => $this->nodes[1]->getEntityTypeId() . ':' . $this->nodes[1]->id() . ' ' . $this->nodes[0]->getEntityTypeId() . ':' . $this->nodes[0]->id(),
+    ];
+    $this->drupalPostForm(NULL, $edit, 'Submit');
+    $expected = 'Selected entities: ' . $this->nodes[1]->label() . ', ' . $this->nodes[0]->label();
+    $this->assertText($expected, 'Selected entities detected.');
+  }
+
+}
\ No newline at end of file
diff --git a/tests/modules/entity_browser_test/entity_browser_test.routing.yml b/tests/modules/entity_browser_test/entity_browser_test.routing.yml
new file mode 100644
index 0000000..7917815
--- /dev/null
+++ b/tests/modules/entity_browser_test/entity_browser_test.routing.yml
@@ -0,0 +1,7 @@
+entity_browser_test.element:
+  path: '/test-element'
+  defaults:
+    _form: '\Drupal\entity_browser_test\Form\FormElementTest'
+    _title: 'Entity browser form element test'
+  requirements:
+    _access: 'TRUE'
diff --git a/tests/modules/entity_browser_test/src/Form/FormElementTest.php b/tests/modules/entity_browser_test/src/Form/FormElementTest.php
new file mode 100644
index 0000000..a316237
--- /dev/null
+++ b/tests/modules/entity_browser_test/src/Form/FormElementTest.php
@@ -0,0 +1,62 @@
+<?php
+
+namespace Drupal\entity_browser_test\Form;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\FormStateInterface;
+
+/**
+ * Provides a user login form.
+ */
+class FormElementTest extends FormBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getFormId() {
+    return 'entity_browser_test_element';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state) {
+    $form['#cache']['max-age'] = 0;
+
+    $form['fancy_entity_browser'] = [
+      '#type' => 'entity_browser',
+      '#entity_browser' => 'test_entity_browser_iframe',
+    ];
+
+    if ($default = \Drupal::request()->get('default_entity')) {
+      list($entity_type, $entity_id) = explode(':', $default);
+      $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
+      $form['fancy_entity_browser']['#default_value'] = [$entity];
+    }
+
+    $form['main_submit'] = [
+      '#type' => 'submit',
+      '#value' => $this->t('Submit'),
+    ];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, FormStateInterface $form_state) {
+    $entities = $form_state->getValue(['fancy_entity_browser', 'entities']);
+
+    $message = 'Selected entities: ';
+    $message .= implode(', ', array_map(
+      function (EntityInterface $item) {
+        return $item->label();
+      },
+      $entities
+    ));
+    drupal_set_message($message);
+  }
+
+}
