diff --git a/src/Element/ComponentElementBuilder.php b/src/Element/ComponentElementBuilder.php
index d890b3599b5123ebcde07d5bba5639816d3a6f7f..e2948b34e57d6a2739782c9dd7d8389d1eca881f 100644
--- a/src/Element/ComponentElementBuilder.php
+++ b/src/Element/ComponentElementBuilder.php
@@ -4,14 +4,14 @@ declare(strict_types=1);
 
 namespace Drupal\ui_patterns\Element;
 
+use Drupal\ui_patterns\Plugin\UiPatterns\PropType\SlotPropType;
 use Drupal\Component\Plugin\Exception\ContextException;
 use Drupal\Core\Plugin\Component;
 use Drupal\Core\Render\Element;
 use Drupal\Core\Security\TrustedCallbackInterface;
 use Drupal\Core\Theme\ComponentPluginManager;
 use Drupal\ui_patterns\ComponentPluginManager as UiPatternsComponentPluginManager;
-use Drupal\ui_patterns\PropTypePluginManager;
-use Drupal\ui_patterns\SourceInterface;
+use Drupal\ui_patterns\PropTypeInterface;
 use Drupal\ui_patterns\SourcePluginBase;
 use Drupal\ui_patterns\SourcePluginManager;
 use Psr\Log\LoggerInterface;
@@ -34,7 +34,6 @@ class ComponentElementBuilder implements TrustedCallbackInterface {
    */
   public function __construct(
     protected SourcePluginManager $sourcesManager,
-    protected PropTypePluginManager $propTypeManager,
     protected ComponentPluginManager $componentPluginManager,
     protected ModuleHandlerInterface $moduleHandler,
     protected LoggerInterface $logger,
@@ -79,75 +78,86 @@ class ComponentElementBuilder implements TrustedCallbackInterface {
    * Add a single prop to the renderable.
    */
   protected function buildProp(array $build, string $prop_id, array $definition, array $configuration, array $source_contexts): array {
-    if (isset($build["#props"][$prop_id])) {
+    if (isset($build['#props'][$prop_id])) {
       // Keep existing props. No known use case yet.
       return $build;
     }
-    $source = $this->getSource($prop_id, $definition, $configuration, $source_contexts);
-    if (!$source) {
-      return $build;
+    return $this->buildSource($build, $prop_id, $definition, $configuration, $source_contexts);
+  }
+
+  /**
+   * Add data to a prop or a slot.
+   */
+  protected function addDataToComponent(array &$build, string $prop_or_slot_id, PropTypeInterface $prop_type, mixed $data): void {
+    if ($prop_type instanceof SlotPropType) {
+      if ($data !== NULL && Element::isRenderArray($data)) {
+        if ($this->isSingletonRenderArray($data)) {
+          $data = array_values($data)[0];
+        }
+        $build['#slots'][$prop_or_slot_id][] = $data;
+      }
     }
-    try {
-      $build = $source->alterComponent($build);
-      $prop_type = $definition['ui_patterns']['type_definition'];
-      $data = $source->getValue($prop_type);
-      $this->moduleHandler->alter('ui_patterns_source_value', $data, $source, $configuration);
-      if (empty($data) && $prop_type->getPluginId() !== 'attributes') {
+    else {
+      if (!empty($data) || $prop_type->getPluginId() === 'attributes') {
         // For JSON Schema validator, empty value is not the same as missing
         // value, and we want to prevent some of the prop types rules to be
-        // applied on empty values: string pattern, string format, enum, number
-        // min/max...
+        // applied on empty values: string pattern, string format,
+        // enum, number min/max...
         // However, we don't remove empty attributes to avoid an error with
         // Drupal\Core\Template\TwigExtension::createAttribute() when themers
         // forget to use the default({}) filter.
-        return $build;
+        $build['#props'][$prop_or_slot_id] = $data;
       }
-      $build["#props"][$prop_id] = $data;
     }
-    catch (ContextException $e) {
-      // ContextException is thrown when a required context is missing.
-      // We don't want to break the render process, so we just ignore the prop.
-      $error_message = t("Context error for prop '@prop_id' in component '@component_id': @message", [
-        '@prop_id' => $prop_id,
-        '@component_id' => $build['#component'],
-        '@message' => $e->getMessage(),
-      ]);
-      $this->logger->error($error_message);
-    }
-    return $build;
   }
 
   /**
-   * Get Source plugin for a prop.
+   * Update the build array for a configured source on a prop/slot.
    *
+   * @param array $build
+   *   The build array.
    * @param string $prop_or_slot_id
    *   Prop ID or slot ID.
    * @param array $definition
    *   Definition.
    * @param array $configuration
    *   Configuration.
-   * @param array $source_contexts
+   * @param array $contexts
    *   Source contexts.
    *
-   * @return \Drupal\ui_patterns\SourceInterface|null
-   *   The source found or NULL.
-   *
-   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   * @return mixed
+   *   The updated build array.
    */
-  protected function getSource(string $prop_or_slot_id, array $definition, array $configuration, array $source_contexts) : ?SourceInterface {
-    $source_id = $configuration["source_id"] ?? NULL;
-    if (!$source_id && isset($definition['ui_patterns']['type_definition'])) {
-      $source_id = $this->sourcesManager->getPropTypeDefault($definition['ui_patterns']['type_definition']->getPluginId(), $source_contexts);
+  public function buildSource(array $build, string $prop_or_slot_id, array $definition, array $configuration, array $contexts) : mixed {
+    try {
+      if (empty($configuration['source_id'])) {
+        return $build;
+      }
+      $source = $this->sourcesManager->getSource($prop_or_slot_id, $definition, $configuration, $contexts);
+      if (!$source) {
+        return $build;
+      }
+      /** @var \Drupal\ui_patterns\PropTypeInterface $prop_type */
+      $prop_type = $source->getPropDefinition()['ui_patterns']['type_definition'];
+      // Alter the build array before getting the value.
+      $build = $source->alterComponent($build);
+      // Get the value from the source.
+      $data = $source->getValue($prop_type);
+      // Alter the value by hook implementations.
+      $this->moduleHandler->alter('ui_patterns_source_value', $data, $source, $configuration);
+      $this->addDataToComponent($build, $prop_or_slot_id, $prop_type, $data);
     }
-    if (!$source_id) {
-      return NULL;
+    catch (ContextException $e) {
+      // ContextException is thrown when a required context is missing.
+      // We don't want to break the render process, so we just ignore the prop.
+      $error_message = t("Context error for '@prop_id' in component '@component_id': @message", [
+        '@prop_id' => $prop_or_slot_id,
+        '@component_id' => $build['#component'],
+        '@message' => $e->getMessage(),
+      ]);
+      $this->logger->error($error_message);
     }
-    /** @var \Drupal\ui_patterns\SourceInterface $source */
-    $source = $this->sourcesManager->createInstance(
-      $source_id,
-      SourcePluginBase::buildConfiguration($prop_or_slot_id, $definition, $configuration, $source_contexts)
-    );
-    return $source;
+    return $build;
   }
 
   /**
@@ -167,34 +177,22 @@ class ComponentElementBuilder implements TrustedCallbackInterface {
    * Add a single slot to the renderable.
    */
   protected function buildSlot(array $build, string $slot_id, array $definition, array $configuration, array $contexts): array {
-    if (isset($build["#slots"][$slot_id])) {
+    if (isset($build['#slots'][$slot_id])) {
       // Keep existing slots. Used by ComponentLayout for example.
       return $build;
     }
-    if (!isset($configuration["sources"])) {
+    if (!isset($configuration['sources'])) {
       return $build;
     }
     // Slots can have many sources while props can have only one.
-    $build["#slots"][$slot_id] = [];
-    /** @var \Drupal\ui_patterns\PropTypeInterface $slot_prop_type */
-    $slot_prop_type = $this->propTypeManager->createInstance("slot", []);
+    $build['#slots'][$slot_id] = [];
     // Add sources data to the slot.
-    foreach ($configuration["sources"] as $source_configuration) {
-      $source = $this->getSource($slot_id, $definition, $source_configuration, $contexts);
-      if (!$source) {
-        continue;
-      }
-      $build = $source->alterComponent($build);
-      $source_value = $source->getValue($slot_prop_type) ?? [];
-      $this->moduleHandler->alter('ui_patterns_source_value', $source_value, $source, $source_configuration);
-      if (Element::isRenderArray($source_value)) {
-        $build["#slots"][$slot_id][] = $this->isSingletonRenderArray($source_value) ? array_values($source_value)[0] : $source_value;
-      }
+    foreach ($configuration['sources'] as $source_configuration) {
+      $build = $this->buildSource($build, $slot_id, $definition, $source_configuration, $contexts);
     }
-    if ($this->isSingletonRenderArray($build["#slots"][$slot_id])) {
-      $build["#slots"][$slot_id] = $build["#slots"][$slot_id][0];
+    if ($this->isSingletonRenderArray($build['#slots'][$slot_id])) {
+      $build['#slots'][$slot_id] = $build['#slots'][$slot_id][0];
     }
-
     return $build;
   }
 
@@ -269,7 +267,7 @@ class ComponentElementBuilder implements TrustedCallbackInterface {
       if ($prop_id === 'variant') {
         continue;
       }
-      if ($source = $this->getSource($prop_id, $definition, $configuration['props'][$prop_id] ?? [], $contexts)) {
+      if ($source = $this->sourcesManager->getSource($prop_id, $definition, $configuration['props'][$prop_id] ?? [], $contexts)) {
         SourcePluginBase::mergeConfigDependencies($dependencies, $source->calculateDependencies());
       }
     }
@@ -294,11 +292,11 @@ class ComponentElementBuilder implements TrustedCallbackInterface {
     $slots = $component->metadata->slots ?? [];
     foreach ($slots as $slot_id => $definition) {
       $slot_configuration = $configuration['slots'][$slot_id] ?? [];
-      if (!isset($slot_configuration["sources"]) || !is_array($slot_configuration["sources"])) {
+      if (!isset($slot_configuration['sources']) || !is_array($slot_configuration['sources'])) {
         continue;
       }
-      foreach ($slot_configuration["sources"] as $source_configuration) {
-        if ($source = $this->getSource($slot_id, $definition, $source_configuration, $contexts)) {
+      foreach ($slot_configuration['sources'] as $source_configuration) {
+        if ($source = $this->sourcesManager->getSource($slot_id, $definition, $source_configuration, $contexts)) {
           SourcePluginBase::mergeConfigDependencies($dependencies, $source->calculateDependencies());
         }
       }
diff --git a/src/SourcePluginManager.php b/src/SourcePluginManager.php
index 32a42c61efe3234537fad3279071e4fdaa39154c..de07ef0df79b3550aed78da1dcc152deb91ebc29 100644
--- a/src/SourcePluginManager.php
+++ b/src/SourcePluginManager.php
@@ -325,4 +325,55 @@ class SourcePluginManager extends DefaultPluginManager implements ContextAwarePl
     return isset($definitions[$source_id]);
   }
 
+  /**
+   * Get a source plugin Instance.
+   *
+   * A source instance is always related to a prop or a slot.
+   * That's why we pass first the prop or slot id and the associated definition.
+   * If definition is empty, the slot will be automatically assumed.
+   * The configuration passed is the source configuration.
+   * It has a key 'source_id' that is the source plugin identifier.
+   * When no source_id is provided,
+   * the default source for the prop type is used.
+   * The source contexts are the contexts currently in use,
+   * maybe needed for that source or not.
+   * The form array parents are the form array parents, needed
+   * when dealing with the source settingsForm.
+   *
+   * @param string $prop_or_slot_id
+   *   Prop ID or slot ID.
+   * @param array $definition
+   *   Definition (if empty, slot will be automatically set).
+   * @param array $configuration
+   *   Configuration for the source.
+   * @param array $source_contexts
+   *   Source contexts.
+   * @param array $form_array_parents
+   *   Form array parents.
+   *
+   * @return \Drupal\ui_patterns\SourceInterface|null
+   *   The source found and instantiated or NULL.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\PluginException
+   */
+  public function getSource(string $prop_or_slot_id, array $definition, array $configuration, array $source_contexts = [], array $form_array_parents = []) : ?SourceInterface {
+    if (empty($definition)) {
+      // We consider a slot if no definition is provided.
+      $definition = ['ui_patterns' => ['type_definition' => $this->propTypeManager->createInstance('slot')]];
+    }
+    $source_id = $configuration['source_id'] ?? NULL;
+    if (!$source_id && isset($definition['ui_patterns']['type_definition'])) {
+      $source_id = $this->getPropTypeDefault($definition['ui_patterns']['type_definition']->getPluginId(), $source_contexts);
+    }
+    if (!$source_id) {
+      return NULL;
+    }
+    /** @var \Drupal\ui_patterns\SourceInterface $source */
+    $source = $this->createInstance(
+      $source_id,
+      SourcePluginBase::buildConfiguration($prop_or_slot_id, $definition, $configuration, $source_contexts, $form_array_parents)
+    );
+    return $source;
+  }
+
 }
diff --git a/ui_patterns.services.yml b/ui_patterns.services.yml
index ac131fbe71b9ee6e89c909bbbf4b87204a807612..fc03ba97b7e551760eee99f5ca889bee305288c5 100644
--- a/ui_patterns.services.yml
+++ b/ui_patterns.services.yml
@@ -44,7 +44,6 @@ services:
     class: Drupal\ui_patterns\Element\ComponentElementBuilder
     arguments:
       - "@plugin.manager.ui_patterns_source"
-      - "@plugin.manager.ui_patterns_prop_type"
       - "@plugin.manager.sdc"
       - "@module_handler"
       - "@logger.channel.ui_patterns"