diff --git a/app/models/communication/block/component/organization.rb b/app/models/communication/block/component/organization.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f9206289398bdbf1bd17530baec38f5d3a1b074b
--- /dev/null
+++ b/app/models/communication/block/component/organization.rb
@@ -0,0 +1,7 @@
+class Communication::Block::Component::Organization < Communication::Block::Component::Base
+
+  def organization
+    template.block.university.organizations.find_by(id: data)
+  end
+
+end
diff --git a/app/models/communication/block/template/page.rb b/app/models/communication/block/template/page.rb
index c0bfa1ac6bde0fc6d91b28c10bf39903dc7ac7af..578ad8a652731b0ff14a5264e0042b234b5e2de0 100644
--- a/app/models/communication/block/template/page.rb
+++ b/app/models/communication/block/template/page.rb
@@ -1,19 +1,12 @@
 class Communication::Block::Template::Page < Communication::Block::Template::Base
 
   has_layouts [:grid, :list, :cards]
+  has_elements Communication::Block::Template::Page::Element
+  has_component :mode, :option, options: [:selection, :children]
   has_component :text, :rich_text
 
-  def build_git_dependencies
-    add_dependency main_page
-    selected_pages.each do |page|
-      add_dependency page
-      add_dependency page.active_storage_blobs
-    end
-  end
-
   def selected_pages
-    # kind could be: selection (default), children
-    @selected_pages ||= send "selected_pages_#{kind}"
+    @selected_pages ||= send "selected_pages_#{mode}"
   end
 
   def main_page
@@ -34,13 +27,10 @@ class Communication::Block::Template::Page < Communication::Block::Template::Bas
 
   protected
 
-  def kind
-    @kind ||= data['kind'] || 'selection'
-  end
-
   def selected_pages_selection
+    return []
     elements.map { |element|
-      page element['id']
+      element.page
     }.compact
   end
 
diff --git a/app/models/communication/block/template/page/element.rb b/app/models/communication/block/template/page/element.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c785d9d93c61a10e59c7ef4ae04c7194bf0d0885
--- /dev/null
+++ b/app/models/communication/block/template/page/element.rb
@@ -0,0 +1,3 @@
+class Communication::Block::Template::Page::Element < Communication::Block::Template::Base
+
+end
diff --git a/app/models/communication/block/template/partner.rb b/app/models/communication/block/template/partner.rb
index 4a19277ae9e131ba53fb97213b3f164115ae7065..6d3b2d286d3506503a6e48ed1ecb356297149e7b 100644
--- a/app/models/communication/block/template/partner.rb
+++ b/app/models/communication/block/template/partner.rb
@@ -1,47 +1,51 @@
 class Communication::Block::Template::Partner < Communication::Block::Template::Base
-  def build_git_dependencies
-    add_dependency active_storage_blobs
-    add_dependency organizations
-    organizations.each do |organization|
-      add_dependency organization.active_storage_blobs
-    end
-  end
 
-  def partners
-    @partners ||= elements.map { |element|
-      partner(element)
-    }.compact
-  end
+  has_elements Communication::Block::Template::Partner::Element
 
-  def active_storage_blobs
-    @active_storage_blobs ||= partners.map { |partner|
-      partner.blob
-    }.compact
-  end
 
-  protected
+  # def build_git_dependencies
+  #   add_dependency active_storage_blobs
+  #   add_dependency organizations
+  #   organizations.each do |organization|
+  #     add_dependency organization.active_storage_blobs
+  #   end
+  # end
+  #
+  # def partners
+  #   @partners ||= elements.map { |element|
+  #     partner(element)
+  #   }.compact
+  # end
 
-  def organizations
-    @organizations ||= partners.map { |partner|
-      partner.organization
-    }.compact
-  end
+  # def active_storage_blobs
+  #   @active_storage_blobs ||= partners.map { |partner|
+  #     partner.blob
+  #   }.compact
+  # end
 
-  def partner(element)
-    # Init to have easy tests in the views and dependencies
-    element['organization'] = nil
-    element['blob'] = nil
-    if element['id']
-      organization = university.organizations.find_by id: element['id']
-      if organization
-        element['organization'] = organization
-        element['name'] = organization.to_s
-        element['url'] = organization.url
-        element['blob'] = organization.logo&.blob
-      end
-    else
-      element['blob'] = find_blob element, 'logo'
-    end
-    element.to_dot
-  end
+  # protected
+
+  # def organizations
+  #   @organizations ||= partners.map { |partner|
+  #     partner.organization
+  #   }.compact
+  # end
+  #
+  # def partner(element)
+  #   # Init to have easy tests in the views and dependencies
+  #   element['organization'] = nil
+  #   element['blob'] = nil
+  #   if element['id']
+  #     organization = university.organizations.find_by id: element['id']
+  #     if organization
+  #       element['organization'] = organization
+  #       element['name'] = organization.to_s
+  #       element['url'] = organization.url
+  #       element['blob'] = organization.logo&.blob
+  #     end
+  #   else
+  #     element['blob'] = find_blob element, 'logo'
+  #   end
+  #   element.to_dot
+  # end
 end
diff --git a/app/models/communication/block/template/partner/element.rb b/app/models/communication/block/template/partner/element.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1c9b6009a198078c59aa601c96911503183c3b53
--- /dev/null
+++ b/app/models/communication/block/template/partner/element.rb
@@ -0,0 +1,24 @@
+class Communication::Block::Template::Partner::Element < Communication::Block::Template::Base
+
+  has_component :id, :organization
+  has_component :name, :string
+  has_component :url, :string
+  has_component :logo, :image
+
+  def organization
+    id_component.organization
+  end
+
+  def best_name
+    organization ? organization.name : name
+  end
+
+  def best_url
+    organization ? organization.url : url
+  end
+
+  def best_logo
+    organization ? organization.logo.blob : logo_component.blob
+  end
+
+end
diff --git a/app/views/admin/communication/blocks/components/organization/_edit.html.erb b/app/views/admin/communication/blocks/components/organization/_edit.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..5657ea94db25c75d1ed1dabb148f0328abbb6989
--- /dev/null
+++ b/app/views/admin/communication/blocks/components/organization/_edit.html.erb
@@ -0,0 +1,21 @@
+<%
+organizations = current_university.organizations.ordered
+%>
+<% unless label.blank? %>
+  <label  class="form-label"
+          :for="<%= dom_id.html_safe %>">
+    <%= label %>
+  </label>
+<% end %>
+<select :id="<%= dom_id.html_safe %>"
+        class="form-select select mb-3"
+        v-model="<%= model %>.<%= property %>">
+  <option value="" :selected="true">
+    <%= t "#{i18n_component}.unregistered" %>
+  </option>
+  <% organizations.each do |organization| %>
+    <option value="<%= organization.id %>">
+      <%= organization.name %>
+    </option>
+  <% end %>
+</select>
diff --git a/app/views/admin/communication/blocks/components/organization/_preview.html.erb b/app/views/admin/communication/blocks/components/organization/_preview.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..e303dbb1e599492d3fab25cb049faed14ea81874
--- /dev/null
+++ b/app/views/admin/communication/blocks/components/organization/_preview.html.erb
@@ -0,0 +1 @@
+<%= component.organization.to_s %>
diff --git a/app/views/admin/communication/blocks/components/organization/_static.html.erb b/app/views/admin/communication/blocks/components/organization/_static.html.erb
new file mode 100644
index 0000000000000000000000000000000000000000..a871dde97f687b000c6124e9bf75784cdd148d18
--- /dev/null
+++ b/app/views/admin/communication/blocks/components/organization/_static.html.erb
@@ -0,0 +1 @@
+<%= indentation %><%= '- ' if list %><%= property %>: <%= value %>
diff --git a/app/views/admin/communication/blocks/templates/partners/_edit.html.erb b/app/views/admin/communication/blocks/templates/partners/_edit.html.erb
index cd3b51853de9304519b47bad410fc7437f67c18f..1492348dcdfdb3736f9723185437ba741815e7df 100644
--- a/app/views/admin/communication/blocks/templates/partners/_edit.html.erb
+++ b/app/views/admin/communication/blocks/templates/partners/_edit.html.erb
@@ -1,9 +1,6 @@
-<a  class="<%= button_classes('mb-4 me-1') %>"
-    v-on:click="data.elements.push({id:'', name: '', url: '', logo: {}})">
-    <%= t '.add_partner' %>
-</a>
+<%= block_component_add_element t('.add_partner') %>
 <draggable :list="data.elements" class="list-group" handle=".partnerHandle">
-  <div v-for="(partner, index) in data.elements" class="list-group-item">
+  <div v-for="(element, index) in data.elements" class="list-group-item">
     <div class="d-flex">
       <div>
         <a class="btn ps-0 pt-0 partnerHandle">
@@ -13,62 +10,18 @@
       <div class="flex-fill">
         <div class="row">
          <div class="col-lg-4">
-            <select :id="'organization-' + index + '-id'"
-                    class="form-select select"
-                    v-model="partner.id">
-              <option value="" :selected="true"><%= t '.unregistered_organization' %></option>
-              <% current_university.organizations.ordered.each_with_index do |organization, index| %>
-                <option value="<%= organization.id %>"><%= organization.name %></option>
-              <% end %>
-            </select>
+           <%= block_component_edit :id, template: @element, label: '' %>
           </div>
         </div>
-        <div class="row mt-3"  v-if="!partner.id">
+        <div class="row"  v-if="!element.id">
           <div class="col-lg-4">
-            <label  class="form-label"
-                    :for="'partner-' + index + '-name'"><%= t '.partner_name_label' %></label>
-
-            <input class="form-control mb-3"
-                  type="text"
-                  v-model="partner.name"
-                  placeholder="<%= t '.partner_name_placeholder' %>"
-                  :id="'partner-' + index + '-name'">
+            <%= block_component_edit :name, template: @element %>
           </div>
           <div class="col-lg-4">
-            <label  class="form-label"
-                    :for="'partner-' + index + '-url'">
-              <%= t '.partner_url_label' %>
-            </label>
-            <input class="form-control mb-3"
-                  type="url"
-                  v-model="partner.url"
-                  placeholder="<%= t '.partner_url_placeholder' %>"
-                  :id="'partner-' + index + '-url'">
+            <%= block_component_edit :url, template: @element %>
           </div>
           <div class="col-lg-4">
-            <div v-if="!partner.logo.id">
-              <%# TODO : create a uploader vue3 component %>
-              <label  class="form-label"
-                      :for="'partner-' + index + '-logo'">
-                <%= t '.partner_logo_label' %>
-              </label>
-              <input  class="form-control mb-3"
-                      type="file"
-                      accept="image/*"
-                      @change="onFileImageChange( $event, partner, 'logo' )"
-                      :id="'partner-' + index + '-logo'">
-            </div>
-            <div v-if="partner.logo.id">
-              <img :src="getImageUrl(partner.logo)"
-                    class="img-fluid"
-                    style="max-height: 80px"
-                    />
-              <a  class="btn btn-sm btn-danger ms-2"
-                  v-on:click="partner.logo={}">
-                  <i class="fas fa-times"></i>
-                  <%= t '.remove_logo' %>
-              </a>
-            </div>
+            <%= block_component_edit :logo, template: @element %>
           </div>
         </div>
       </div>
diff --git a/app/views/admin/communication/blocks/templates/partners/_preview.html.erb b/app/views/admin/communication/blocks/templates/partners/_preview.html.erb
index 989a14a51f02d21ed622135ce2120ebecea75d71..0498531d17f301ee65cba33c290db68e97690447 100644
--- a/app/views/admin/communication/blocks/templates/partners/_preview.html.erb
+++ b/app/views/admin/communication/blocks/templates/partners/_preview.html.erb
@@ -1,11 +1,15 @@
-<% @block.template.partners.each do |partner| %>
-  <article class="card">
-    <%= kamifusen_tag partner.blob,
-                      width: 300,
-                      class: 'img-fluid mb-3' unless partner.blob.nil? %>
-    <div class="card-body">
-      <h3 class="card-title h5"><%= partner.name %></h3>
-      <p class="mb-0"><%= partner.url %></p>
+<div class="row">
+  <% @block.template.elements.each do |element| %>
+    <div class="col-6 mb-3">
+      <%= kamifusen_tag element.best_logo,
+                        width: 600,
+                        class: 'img-fluid mb-2' unless element.best_logo.nil? %>
+      <p>
+        <%= element.best_name %><br>
+        <span class="small">
+          <%= element.best_url %>
+        </span>
+      </p>
     </div>
-  </article>
-<% end %>
+  <% end %>
+</div>
diff --git a/app/views/admin/communication/blocks/templates/partners/_static.html.erb b/app/views/admin/communication/blocks/templates/partners/_static.html.erb
index c9b3159170012285247e60bad2994e9ddb540fbd..8785dd5739964b86a75d18c00b828bfcfe35a207 100644
--- a/app/views/admin/communication/blocks/templates/partners/_static.html.erb
+++ b/app/views/admin/communication/blocks/templates/partners/_static.html.erb
@@ -1,11 +1,10 @@
-<% block.template.partners.each do |partner|
-      if partner.organization %>
-      - slug: "<%= partner.organization.slug %>"
-      <% else %>
-      - name: >
-          <%= prepare_text_for_static partner['name'], 5 %>
-        url: >-
-          <%= prepare_text_for_static partner['url'], 5 %>
-        logo: "<%= partner.blob&.id %>"
-      <% end %>
+<%
+block.template.elements.each do |element| %>
+<% if element.organization %>
+      - slug: "<%= element.organization.slug %>"
+<% else %>
+<%= block_component_static :name, template: element, list: true %>
+<%= block_component_static :url, template: element, depth: 4 %>
+        logo: "<%= element.logo_component.blob&.id %>"
+<% end %>
 <% end %>
diff --git a/config/locales/communication/fr.yml b/config/locales/communication/fr.yml
index 30aa26e4f57137e07a3c51398e9bf7f3443c1a64..f3800e9af8bf624fef6728f5dca1d4e0d0ea27ee 100644
--- a/config/locales/communication/fr.yml
+++ b/config/locales/communication/fr.yml
@@ -320,13 +320,20 @@ fr:
             description: Une liste de partenaires, avec leur logo, leur site et leur nom.
             edit:
               add_partner: Ajouter un partenaire
-              partner_name_label: Partenaire
-              partner_name_placeholder: Entrer le nom du partenaire
-              partner_url_label: Site Web
-              partner_url_placeholder: https://
-              partner_logo_label: Logo
-              remove_logo: Enlever le logo
-              remove_partner: Enlever le partenaire
+              element:
+                id:
+                  label: Organisation
+                  placeholder: Choisir l'organisation
+                  unregistered: Organisation non enregistrée
+                name:
+                  label: Nom
+                  placeholder: Entrer le nom du partenaire
+                url:
+                  label: Site Web
+                  placeholder: https://
+                logo_label: Logo
+                remove_logo: Enlever le logo
+                remove_partner: Enlever le partenaire
           posts:
             description: Une liste d'actualités mises en avant.
             edit: