diff --git a/conditional_fields.api.php b/conditional_fields.api.php
new file mode 100644
index 0000000..51f6285
--- /dev/null
+++ b/conditional_fields.api.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Hooks for the conditional_fields module.
+ */
+
+/**
+ * @addtogroup hooks
+ * @{
+ */
+
+/**
+ * Build a list of available fields.
+ *
+ * @param string $entity_type
+ *   Name of the entity type being configured.
+ * @param string $bundle_name
+ *   Name of the entity bundle being configured.
+ * @return array Fields provided by this module.
+ *   Keyed by machine name, with field labels as values.
+ */
+function hook_conditional_fields($entity_type, $bundle_name) {
+  $fields = [];
+  $group_info = field_group_info_groups($entity_type, $bundle_name, 'form', 'default');
+  foreach ($group_info as $name => $group) {
+    $fields[$name] = $group->label;
+  }
+  return $fields;
+}
+
+/**
+ * Alter the list of available fields.
+ *
+ * @param string $entity_type
+ *   Name of the entity type being configured.
+ * @param string $bundle_name
+ *   Name of the entity bundle being configured.
+ * @param string $fields
+ *   Fields available to this module, provided by modules that implement
+ *   hook_conditional_fields().
+ */
+function hook_conditional_fields_alter(&$fields, $entity_type, $bundle_name) {
+  asort($fields);
+}
+
+/**
+ * @} End of "addtogroup hooks".
+ */
diff --git a/conditional_fields.module b/conditional_fields.module
index e22afb9..2ca431e 100644
--- a/conditional_fields.module
+++ b/conditional_fields.module
@@ -147,6 +147,28 @@ function conditional_fields_element_info_alter(array &$types) {
   }
 }
 
+/**
+ * Implements hook_conditional_fields().
+ *
+ * We implement this on behalf of the core Field module.
+ */
+function conditional_fields_conditional_fields($entity_type, $bundle_name) {
+  $fields = [];
+  $instances = \Drupal::getContainer()->get("entity_field.manager")
+    ->getFieldDefinitions($entity_type, $bundle_name);
+  foreach ($instances as $field) {
+    $fields[$field->getName()] = $field->getLabel();
+  }
+  return $fields;
+}
+
+/**
+ * Implements hook_conditional_fields_alter().
+ */
+function conditional_fields_conditional_fields_alter(&$fields, $entity_type, $bundle_name) {
+  asort($fields);
+}
+
 /**
  * Processes form elements with dependencies.
  *
diff --git a/src/ConditionalFieldsFormHelper.php b/src/ConditionalFieldsFormHelper.php
index 991c321..c460694 100644
--- a/src/ConditionalFieldsFormHelper.php
+++ b/src/ConditionalFieldsFormHelper.php
@@ -16,6 +16,11 @@ class ConditionalFieldsFormHelper {
 
   protected $form;
   protected $form_state;
+  protected $effects;
+  protected $dependent_location;
+  protected $dependent_form_field;
+  /*  List of all form states. */
+  protected $states;
 
   /**
    * An after_build callback for forms with dependencies.
@@ -32,91 +37,116 @@ class ConditionalFieldsFormHelper {
       return $this->form;
     }
 
-    $effects = [];
+    $this->processDependentFields();
+    $this->addJavascriptEffects();
+    $this->addValidationCallback();
+
+    return $this->form;
+  }
+
+  /**
+   * Build and attach #states properties to dependent fields.
+   */
+  protected function processDependentFields() {
+    $this->effects = [];
 
     // Cycle all dependents.
-    foreach ($form['#conditional_fields'] as $dependent => $dependent_info) {
-      $states = [];
+    foreach ($this->form['#conditional_fields'] as $dependent => $dependent_info) {
+      $this->states = [];
 
-      if (empty($dependent_info['dependees'])) {
+      $dependees = $dependent_info['dependees'];
+      if (empty($dependees)) {
         continue;
       }
 
-      $dependent_location = array_merge([], [$dependent]);
-      $dependent_form_field = NestedArray::getValue($form, $dependent_location);
+      $this->dependent_location = array_merge([], [$dependent]);
+      $this->dependent_form_field = NestedArray::getValue($this->form, $this->dependent_location);
 
-      // Cycle the dependant's dependees.
-      foreach ($dependent_info['dependees'] as $dependency) {
-        $dependee = $dependency['dependee'];
+      $this->processDependeeFields($dependees);
 
-        if (empty($form['#conditional_fields'][$dependee])) {
-          continue;
-        }
-
-        $dependee_info = $form['#conditional_fields'][$dependee];
+      if (empty($this->states)) {
+        continue;
+      }
 
-        end($dependee_info['parents']);
-        $unset = key($dependee_info['parents']);
-        if (is_int($dependee_info['parents'][$unset]) && $dependee_info['parents'][$unset] > 0) {
-          unset($dependee_info['parents'][$unset]);
-        }
+      // Save the modified field back into the form.
+      NestedArray::setValue($this->form, $this->dependent_location, $this->dependent_form_field);
 
-        $dependee_form_field = NestedArray::getValue($form, $dependee_info['parents']);
-        $options = $dependency['options'];
+      // Add the #states property to the dependent field.
+      NestedArray::setValue($this->form, array_merge($this->dependent_location, ['#states']), $this->mapStates());
+    }
 
-        if (!empty($options['values']) && is_string($options['values'])) {
-          $options['values'] = explode("\r\n", $options['values']);
-        }
+  }
 
-        $options['selector'] = self::getSelector($options['selector'], $dependee_form_field);
+  /**
+   * Determine and register dependee field effects.
+   */
+  protected function processDependeeFields($dependees) {
+    // Cycle the dependant's dependees.
+    foreach ($dependees as $dependency) {
+      $dependee = $dependency['dependee'];
 
-        $state = $this->getState($dependee, $dependee_form_field, $options);
+      if (empty($this->form['#conditional_fields'][$dependee])) {
+        continue;
+      }
 
-        // Add validation callback to element if the dependency can be evaluated.
-        if (in_array($options['condition'], [
-          'value',
-          'empty',
-          '!empty',
-          'checked',
-          '!checked',
-        ])) {
-        self::elementAddProperty($dependent_form_field, '#element_validate', [self::class, 'dependentValidate'], 'append');
-        }
+      $dependee_info = $this->form['#conditional_fields'][$dependee];
 
-        self::addStateToGroup($states, $state, $options);
+      end($dependee_info['parents']);
+      $unset = key($dependee_info['parents']);
+      if (is_int($dependee_info['parents'][$unset]) && $dependee_info['parents'][$unset] > 0) {
+        unset($dependee_info['parents'][$unset]);
+      }
 
-        $selector = conditional_fields_field_selector(NestedArray::getValue($form, [$dependent_location[0]]));
-        $effects[$selector] = self::getEffect($options);
+      $dependee_form_field = NestedArray::getValue($this->form, $dependee_info['parents']);
+      $options = $dependency['options'];
 
+      if (!empty($options['values']) && is_string($options['values'])) {
+        $options['values'] = explode("\r\n", $options['values']);
       }
 
-      if (empty($states)) {
-        continue;
+      $options['selector'] = self::getSelector($options['selector'], $dependee_form_field);
+
+      $state = $this->getState($dependee, $dependee_form_field, $options);
+
+      // Add validation callback to element if the dependency can be evaluated.
+      if (in_array($options['condition'], [
+        'value',
+        'empty',
+        '!empty',
+        'checked',
+        '!checked',
+      ])) {
+      self::elementAddProperty($this->dependent_form_field, '#element_validate', [self::class, 'dependentValidate'], 'append');
       }
 
-      // Save the modified field back into the form.
-      NestedArray::setValue($form, $dependent_location, $dependent_form_field);
+      $this->addStateToGroup($state, $options);
 
-      // Add the #states property to the dependent field.
-      $states = self::mapStates($states);
-      NestedArray::setValue($form, array_merge($dependent_location, ['#states']), $states);
+      $selector = conditional_fields_field_selector(NestedArray::getValue($this->form, [$this->dependent_location[0]]));
+      $this->effects[$selector] = self::getEffect($options);
     }
+  }
 
-    $form['#attached']['library'][] = 'conditional_fields/conditional_fields';
+  /**
+   * Add our Javascript and effects.
+   */
+  protected function addJavascriptEffects() {
+    $this->form['#attached']['library'][] = 'conditional_fields/conditional_fields';
     // Add effect settings to the form.
-    if ($effects) {
-      $form['#attached']['drupalSettings']['conditionalFields'] = [
-        'effects' => $effects,
+    if ($this->effects) {
+      $this->form['#attached']['drupalSettings']['conditionalFields'] = [
+        'effects' => $this->effects,
       ];
     }
+  }
 
-    // Validation callback to manage dependent fields validation.
-    $form['#validate'][] = [self::class, 'formValidate'];
+  /**
+   * Add validation callback to manage dependent fields validation.
+   */
+  protected function addValidationCallback() {
+    $this->form['#validate'][] = [self::class, 'formValidate'];
     // Initialize validation information every time the form is rendered to avoid
     // stale data after a failed submission.
-    $form_state->setValue('conditional_fields_untriggered_dependents', []);
-
-    return $form;
+    $this->form_state->setValue('conditional_fields_untriggered_dependents', []);
   }
 
   /**
@@ -212,21 +242,19 @@ class ConditionalFieldsFormHelper {
   /**
    * Merge field states to general list.
    *
-   * @param array $states
-   *   List of all form states.
    * @param array $state
    *   List of field states.
    * @param array $options
    *   Field CF settings.
    */
-  protected static function addStateToGroup(&$states, $state, $options) {
+  protected function addStateToGroup($state, $options) {
     // Add the $state into the correct logic group in $states.
     foreach ($state as $key => $constraints) {
-      if (empty($states[$key][$options['grouping']])) {
-        $states[$key][$options['grouping']] = $constraints;
+      if (empty($this->states[$key][$options['grouping']])) {
+        $this->states[$key][$options['grouping']] = $constraints;
       }
       else {
-        $states[$key][$options['grouping']] = array_merge($states[$key][$options['grouping']], $constraints);
+        $this->states[$key][$options['grouping']] = array_merge($this->states[$key][$options['grouping']], $constraints);
       }
     }
   }
@@ -707,35 +735,29 @@ class ConditionalFieldsFormHelper {
 
   /**
    * Map the states based on the conjunctions.
-   *
-   * @param array $states
-   *   States to map.
-   *
-   * @return array
-   *   Mapped states.
    */
-  protected static function mapStates($states) {
+  protected function mapStates() {
     $states_new = [];
-    foreach ($states as $state_key => $value) {
+    foreach ($this->states as $state_key => $value) {
       // As the main object is ANDed together we can add the AND items directly.
-      if (!empty($states[$state_key]['AND'])) {
-        $states_new[$state_key] = $states[$state_key]['AND'];
+      if (!empty($this->states[$state_key]['AND'])) {
+        $states_new[$state_key] = $this->states[$state_key]['AND'];
       }
       // The OR and XOR groups are moved into a sub-array that has numeric keys
       // so that we get a JSON array and not an object, as required by the States
       // API for OR and XOR groupings.
-      if (!empty($states[$state_key]['OR'])) {
+      if (!empty($this->states[$state_key]['OR'])) {
         $or = [];
-        foreach ($states[$state_key]['OR'] as $constraint_key => $constraint_value) {
+        foreach ($this->states[$state_key]['OR'] as $constraint_key => $constraint_value) {
           $or[] = [$constraint_key => $constraint_value];
         }
         // '1' as a string so that we get an object (which means logic groups
         // are ANDed together).
         $states_new[$state_key]['1'] = $or;
       }
-      if (!empty($states[$state_key]['XOR'])) {
+      if (!empty($this->states[$state_key]['XOR'])) {
         $xor = ['xor'];
-        foreach ($states[$state_key]['XOR'] as $constraint_key => $constraint_value) {
+        foreach ($this->states[$state_key]['XOR'] as $constraint_key => $constraint_value) {
           $xor[] = [$constraint_key => $constraint_value];
         }
         // '2' as a string so that we get an object.
diff --git a/src/Form/ConditionalFieldForm.php b/src/Form/ConditionalFieldForm.php
index b6f9c6b..eeb0aed 100644
--- a/src/Form/ConditionalFieldForm.php
+++ b/src/Form/ConditionalFieldForm.php
@@ -10,6 +10,7 @@ use Drupal\conditional_fields\Conditions;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 
 /**
  * Class ConditionalFieldForm.
@@ -50,6 +51,26 @@ class ConditionalFieldForm extends FormBase {
    */
   protected $list;
 
+  /**
+   * Form array.
+   */
+  protected $form;
+
+  /**
+   * FormState object.
+   */
+  protected $form_state;
+
+  /**
+   * Name of the entity type being configured.
+   */
+  protected $entity_type;
+
+  /**
+   * Name of the entity bundle being configured.
+   */
+  protected $bundle_name;
+
   /**
    * Class constructor.
    *
@@ -61,12 +82,15 @@ class ConditionalFieldForm extends FormBase {
    *   Provides an interface for entity type managers.
    * @param \Drupal\Component\Uuid\UuidInterface $uuid
    *   Uuid generator.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   Manages modules in a Drupal installation.
    */
-  public function __construct(Conditions $list, EntityFieldManagerInterface $entity_field_manager, EntityTypeManagerInterface $entity_type_manager, UuidInterface $uuid) {
+  public function __construct(Conditions $list, EntityFieldManagerInterface $entity_field_manager, EntityTypeManagerInterface $entity_type_manager, UuidInterface $uuid, ModuleHandlerInterface $module_handler) {
     $this->entityFieldManager = $entity_field_manager;
     $this->entityTypeManager = $entity_type_manager;
     $this->list = $list;
     $this->uuidGenerator = $uuid;
+    $this->module_handler = $module_handler;
   }
 
   /**
@@ -79,7 +103,8 @@ class ConditionalFieldForm extends FormBase {
       $container->get('conditional_fields.conditions'),
       $container->get('entity_field.manager'),
       $container->get('entity_type.manager'),
-      $container->get('uuid')
+      $container->get('uuid'),
+      $container->get('module_handler')
     );
   }
 
@@ -94,20 +119,24 @@ class ConditionalFieldForm extends FormBase {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state, $entity_type = NULL, $bundle = NULL) {
+    $this->form = $form;
+    $this->form_state = $form_state;
+    $this->entity_type = $entity_type;
+    $this->bundle_name = $bundle;
 
-    $form['entity_type'] = [
+    $this->form['entity_type'] = [
       '#type' => 'hidden',
-      '#value' => $entity_type,
+      '#value' => $this->entity_type,
     ];
 
-    $form['bundle'] = [
+    $this->form['bundle'] = [
       '#type' => 'hidden',
-      '#value' => $bundle,
+      '#value' => $this->bundle_name,
     ];
 
-    $form['conditional_fields_wrapper']['table'] = $this->buildTable($form, $form_state, $entity_type, $bundle);
+    $this->buildTable();
 
-    return $form;
+    return $this->form;
   }
 
   /**
@@ -138,6 +167,7 @@ class ConditionalFieldForm extends FormBase {
         // Validate required field should be visible.
         $field_instance = $instances[$field];
         if (
+          method_exists($field_instance, 'isRequired') &&
           $field_instance->isRequired() &&
           in_array($state, ['!visible', 'disabled', '!required'])
         ) {
@@ -227,11 +257,11 @@ class ConditionalFieldForm extends FormBase {
   /**
    * Builds table with conditional fields.
    */
-  protected function buildTable(array $form, FormStateInterface $form_state, $entity_type, $bundle_name = NULL) {
-    $form['table'] = [
+  protected function buildTable() {
+    $table = [
       '#type' => 'table',
-      '#entity_type' => $entity_type,
-      '#bundle_name' => $bundle_name,
+      '#entity_type' => $this->entity_type,
+      '#bundle_name' => $this->bundle_name,
       '#header' => [
         $this->t('Target field'),
         $this->t('Controlled by'),
@@ -240,25 +270,18 @@ class ConditionalFieldForm extends FormBase {
       ],
     ];
 
-    // Build list of available fields.
-    $fields = [];
-    $instances = $this->entityFieldManager
-      ->getFieldDefinitions($entity_type, $bundle_name);
-    foreach ($instances as $field) {
-      $fields[$field->getName()] = $field->getLabel() . ' (' . $field->getName() . ')';
-    }
-
-    asort($fields);
+    $fields = $this->getFieldsList();
 
     /* Existing conditions. */
 
     /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $form_display_entity */
     $form_display_entity = $this->entityTypeManager
       ->getStorage('entity_form_display')
-      ->load("$entity_type.$bundle_name.default");
+      ->load("$this->entity_type.$this->bundle_name.default");
 
     if (!$form_display_entity) {
-      return $form['table'];
+      $this->form['conditional_fields_wrapper']['table'] = $table;
+      return;
     }
 
     foreach ($fields as $field_name => $label) {
@@ -275,7 +298,7 @@ class ConditionalFieldForm extends FormBase {
           'uuid' => $uuid,
         ];
 
-        $form['table'][] = [
+        $table[] = [
           'dependent' => ['#markup' => $field_name],
           'dependee' => ['#markup' => $condition['dependee']],
           'state' => ['#markup' => $condition['settings']['state']],
@@ -310,7 +333,7 @@ class ConditionalFieldForm extends FormBase {
     }
 
     // Add new dependency row.
-    $form['table']['add_new_dependency'] = [
+    $table['add_new_dependency'] = [
       'dependent' => [
         '#type' => 'select',
         '#multiple' => TRUE,
@@ -359,9 +382,31 @@ class ConditionalFieldForm extends FormBase {
       ],
     ];
 
-    $form['table']['#attached']['library'][] = 'conditional_fields/admin';
+    $table['#attached']['library'][] = 'conditional_fields/admin';
 
-    return $form['table'];
+    $this->form['conditional_fields_wrapper']['table'] = $table;
+  }
+
+  /**
+   * Return available fields.
+   */
+  protected function getFields() {
+    $fields = $this->module_handler
+      ->invokeAll('conditional_fields', [$this->entity_type, $this->bundle_name]);
+    $this->module_handler
+      ->alter('conditional_fields',$fields, $this->entity_type, $this->bundle_name);
+    return $fields;
+  }
+
+  /**
+   * Build options list of available fields.
+   */
+  protected function getFieldsList() {
+    $fields = [];
+    foreach ($this->getFields() as $name => $label) {
+      $fields[$name] = $label . ' (' . $name . ')';
+    }
+    return $fields;
   }
 
 }
