diff --git a/district/blocks.py b/district/blocks.py
index 2e0bff8b7cebb0d618c604c8fadb5868aa140c50..a1fb75c8175da9d5a20ead1eb4f9429554d2b1cb 100644
--- a/district/blocks.py
+++ b/district/blocks.py
@@ -31,10 +31,47 @@ class AddressBlock(StructBlock):
         label = "Adresa"
 
 
+class SimplePersonBlock(StructBlock):
+    title = blocks.CharBlock(label="Jméno a příjmení", max_length=128, required=True)
+    job = blocks.CharBlock(
+        label="Povolání", max_length=128, required=False, help_text="Např. 'Informatik'"
+    )
+    profile_photo = ImageChooserBlock(label="Profilová fotka", required=False)
+    email = blocks.EmailBlock(label="Email", required=False)
+    city = blocks.CharBlock(label="Město/obec", max_length=64, required=False)
+    age = blocks.IntegerBlock(label="Věk", required=False)
+    is_pirate = blocks.BooleanBlock(
+        label="Je členem Pirátské strany?", default=True, required=False
+    )
+    other_party = blocks.CharBlock(label="Strana", max_length=64, required=False)
+    other_party_logo = ImageChooserBlock(
+        label="Logo strany", required=False, help_text="Vyplňte pokud osoba není Pirát"
+    )
+
+    # socials
+    facebook_url = blocks.URLBlock(label="Odkaz na Facebook", required=False)
+    instagram_url = blocks.URLBlock(label="Odkaz na Instagram", required=False)
+    twitter_url = blocks.URLBlock(label="Odkaz na Twitter", required=False)
+    youtube_url = blocks.URLBlock(label="Odkaz na Youtube kanál", required=False)
+    flickr_url = blocks.URLBlock(label="Odkaz na Flickr", required=False)
+
+    class Meta:
+        icon = "user"
+        label = "Osoba blok"
+
+
 class CandidateListBlock(StructBlock):
-    candidate_list = ListBlock(
-        PageChooserBlock(label="Osoba", page_type=["district.DistrictPersonPage"]),
+    candidate_list = blocks.StreamBlock(
         label="Kandidáti",
+        local_blocks=[
+            (
+                "person_page",
+                PageChooserBlock(
+                    label="Osoba", page_type=["district.DistrictPersonPage"]
+                ),
+            ),
+            ("person_block", SimplePersonBlock()),
+        ],
     )
     candidate_list_big_count = IntegerBlock(
         label="Počet kanditátů s velkým náhledem", default=7
diff --git a/district/migrations/0094_alter_districtelectioncampaignpage_candidates.py b/district/migrations/0094_alter_districtelectioncampaignpage_candidates.py
new file mode 100644
index 0000000000000000000000000000000000000000..216b07030308c2c1f78803af87794dee12417350
--- /dev/null
+++ b/district/migrations/0094_alter_districtelectioncampaignpage_candidates.py
@@ -0,0 +1,252 @@
+# Generated by Django 4.0.4 on 2022-07-22 07:53
+
+import wagtail.blocks
+import wagtail.fields
+import wagtail.images.blocks
+from django.db import migrations
+from wagtail.core.blocks import StreamValue
+
+
+def person_chooser_list_block_to_compact_block(block):
+    for person_page in block["value"]["candidate_list"]:
+        person_page["type"] = "person_page"
+    return block
+
+
+def compact_block_to_person_chooser_list_block(block):
+    for (index, compact_block) in enumerate(block["value"]["candidate_list"]):
+        if compact_block["type"] == "person_page":
+            compact_block["type"] = "item"
+        else:
+            del block["value"]["candidate_list"][index]
+
+    return block
+
+
+def get_content(page, mapper):
+    stream_data = []
+    mapped = False
+
+    for block in page.candidates.raw_data:
+        if block["type"] == "candidates":
+            stream_data.append(mapper(block))
+            mapped = True
+        else:
+            stream_data.append(block)
+
+    return stream_data, mapped
+
+
+def migrate(apps, mapper):
+    DistrictElectionCampaignPage = apps.get_model(
+        "district", "DistrictElectionCampaignPage"
+    )
+
+    for page in DistrictElectionCampaignPage.objects.all():
+        candidates, mapped = get_content(page, mapper)
+
+        if mapped:
+            page.candidates = StreamValue(page.candidates, candidates, is_lazy=True)
+            page.save()
+
+
+def forwards(apps, schema_editor):
+    migrate(apps, person_chooser_list_block_to_compact_block)
+
+
+def backwards(apps, schema_editor):
+    migrate(apps, compact_block_to_person_chooser_list_block)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("district", "0093_alter_districthomepage_subheader"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="districtelectioncampaignpage",
+            name="candidates",
+            field=wagtail.fields.StreamField(
+                [
+                    (
+                        "candidates",
+                        wagtail.blocks.StructBlock(
+                            [
+                                (
+                                    "candidate_list",
+                                    wagtail.blocks.StreamBlock(
+                                        [
+                                            (
+                                                "person_page",
+                                                wagtail.blocks.PageChooserBlock(
+                                                    label="Osoba",
+                                                    page_type=[
+                                                        "district.DistrictPersonPage"
+                                                    ],
+                                                ),
+                                            ),
+                                            (
+                                                "person_block",
+                                                wagtail.blocks.StructBlock(
+                                                    [
+                                                        (
+                                                            "title",
+                                                            wagtail.blocks.CharBlock(
+                                                                label="Jméno a příjmení",
+                                                                max_length=128,
+                                                                required=True,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "job",
+                                                            wagtail.blocks.CharBlock(
+                                                                help_text="Např. 'Informatik'",
+                                                                label="Povolání",
+                                                                max_length=128,
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "profile_photo",
+                                                            wagtail.images.blocks.ImageChooserBlock(
+                                                                label="Profilová fotka",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "email",
+                                                            wagtail.blocks.EmailBlock(
+                                                                label="Email",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "city",
+                                                            wagtail.blocks.CharBlock(
+                                                                label="Město/obec",
+                                                                max_length=64,
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "age",
+                                                            wagtail.blocks.IntegerBlock(
+                                                                label="Věk",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "is_pirate",
+                                                            wagtail.blocks.BooleanBlock(
+                                                                default=True,
+                                                                label="Je členem Pirátské strany?",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "other_party",
+                                                            wagtail.blocks.CharBlock(
+                                                                label="Strana",
+                                                                max_length=64,
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "other_party_logo",
+                                                            wagtail.images.blocks.ImageChooserBlock(
+                                                                help_text="Vyplňte pokud osoba není Pirát",
+                                                                label="Logo strany",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "facebook_url",
+                                                            wagtail.blocks.URLBlock(
+                                                                label="Odkaz na Facebook",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "instagram_url",
+                                                            wagtail.blocks.URLBlock(
+                                                                label="Odkaz na Instagram",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "twitter_url",
+                                                            wagtail.blocks.URLBlock(
+                                                                label="Odkaz na Twitter",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "youtube_url",
+                                                            wagtail.blocks.URLBlock(
+                                                                label="Odkaz na Youtube kanál",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                        (
+                                                            "flickr_url",
+                                                            wagtail.blocks.URLBlock(
+                                                                label="Odkaz na Flickr",
+                                                                required=False,
+                                                            ),
+                                                        ),
+                                                    ]
+                                                ),
+                                            ),
+                                        ],
+                                        label="Kandidáti",
+                                    ),
+                                ),
+                                (
+                                    "candidate_list_big_count",
+                                    wagtail.blocks.IntegerBlock(
+                                        default=7,
+                                        label="Počet kanditátů s velkým náhledem",
+                                    ),
+                                ),
+                                (
+                                    "candidate_list_shown_count",
+                                    wagtail.blocks.IntegerBlock(
+                                        default=16,
+                                        label="Počet zobrazených kandidátů při načtení stránky (včetně velkých náhledů)",
+                                    ),
+                                ),
+                                (
+                                    "cta_text",
+                                    wagtail.blocks.CharBlock(
+                                        label="Text 'call-to-action' baneru",
+                                        required=False,
+                                    ),
+                                ),
+                                (
+                                    "cta_link",
+                                    wagtail.blocks.URLBlock(
+                                        label="Odkaz 'call-to-action' baneru",
+                                        required=False,
+                                    ),
+                                ),
+                                (
+                                    "cta_button_text",
+                                    wagtail.blocks.CharBlock(
+                                        label="Text tlačítka 'call-to-action' baneru",
+                                        max_length=24,
+                                        required=False,
+                                    ),
+                                ),
+                            ]
+                        ),
+                    )
+                ],
+                blank=True,
+                use_json_field=None,
+                verbose_name="Kandidátní listina",
+            ),
+        ),
+        migrations.RunPython(forwards, backwards),
+    ]
diff --git a/district/templates/district/blocks/candidate_list_block.html b/district/templates/district/blocks/candidate_list_block.html
index 7a0a9c33dfb6f74ba6a47745c693a56f7b7e9041..ab752a967825ffa6b7db51f5f625d70f9f567877 100644
--- a/district/templates/district/blocks/candidate_list_block.html
+++ b/district/templates/district/blocks/candidate_list_block.html
@@ -1,11 +1,16 @@
 <div class="candidate-card-list grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4">
-  {% for person_page in self.candidate_list %}
-    {% if forloop.counter <= self.candidate_list_big_count %}
-      {% include "shared/full_candidate_snippet.html" %}
-    {% endif %}
-  {% endfor %}
+    {% for block in self.candidate_list %}
+        {% if forloop.counter <= self.candidate_list_big_count %}
+            {% if block.block_type == 'person_page' %}
+                {% include "shared/full_candidate_snippet.html" with person_page=block.value %}
+            {% endif %}
+            {% if block.block_type == 'person_block' %}
+                {% include "shared/blocks/full_candidate_snippet_block.html" with block=block.value %}
+            {% endif %}
+        {% endif %}
+    {% endfor %}
 
-  {% if self.cta_text%}
+  {% if self.cta_text %}
     <aside class="banner bg-black text-white container-padding--zero sm:container-padding--auto">
       <i class="ico--pirati banner__icon"></i>
       <div class="banner__body">
@@ -27,17 +32,27 @@
 <div>
   <ui-view-provider :initial="{fullCandidateTable: false}" v-slot="{ isCurrentView, setView }">
     <div class="candidate-table pt-8 container-padding--zero lg:container-padding--auto" :class="{'candidate-table--fadeout': !isCurrentView('fullCandidateTable')}">
-      {% for person_page in self.candidate_list %}
+      {% for block in self.candidate_list %}
         {# Záměrně neomezuju list přes indexy, ale ifuju, abych si držel counter pro snippet #}
         {% if forloop.counter > self.candidate_list_big_count and forloop.counter <= self.candidate_list_shown_count  %}
-          {% include "shared/compact_candidate_snippet.html" %}
+            {% if block.block_type == 'person_page' %}
+                {% include "shared/compact_candidate_snippet.html" with person_page=block.value %}
+            {% endif %}
+            {% if block.block_type == 'person_block' %}
+                {% include "shared/blocks/compact_candidate_snippet_block.html" with block=block.value %}
+            {% endif %}
         {% endif %}
       {% endfor %}
       <template v-if="isCurrentView('fullCandidateTable')">
-        {% for person_page in self.candidate_list %}
+        {% for block in self.candidate_list %}
           {# Záměrně neomezuju list přes indexy, ale ifuju, abych si držel counter pro snippet #}
           {% if forloop.counter > self.candidate_list_shown_count  %}
-            {% include "shared/compact_candidate_snippet.html" %}
+            {% if block.block_type == 'person_page' %}
+                {% include "shared/compact_candidate_snippet.html" with person_page=block.value %}
+            {% endif %}
+            {% if block.block_type == 'person_block' %}
+                {% include "shared/blocks/compact_candidate_snippet_block.html" with block=block.value %}
+            {% endif %}
           {% endif %}
         {% endfor %}
       </template>
diff --git a/shared/templates/shared/blocks/compact_candidate_snippet_block.html b/shared/templates/shared/blocks/compact_candidate_snippet_block.html
new file mode 100644
index 0000000000000000000000000000000000000000..3aac6af62bacde3a52cd6b049158385f5d9d2726
--- /dev/null
+++ b/shared/templates/shared/blocks/compact_candidate_snippet_block.html
@@ -0,0 +1,47 @@
+{% load static wagtailimages_tags %}
+
+<div class="candidate-table-row">
+  <div class="candidate-table-row__position head-allcaps-heavy-2xs text-right">
+    <span {% if forloop.counter < 10 %}class="pl-1 pr-1"{% endif %}>
+      {{ forloop.counter }}
+    </span>
+  </div>
+  <div class="avatar avatar--sm candidate-table-row__avatar">
+    {% if block.profile_photo %}
+      {# Match sizing of person_badge_snippet.html to keep the image version count low #}
+      {% image block.profile_photo fill-160x160 as profile_img %}
+      <img src="{{ profile_img.url }}" alt="{{ block.title }}"/>
+    {% else %}
+      <img src="{% static "shared/img/unknown_pirate_160x160.jpg" %}" alt="{{ block.title }}"/>
+    {% endif %}
+  </div>
+  <div class="candidate-table-row__name head-heavy-2xs font-bold">
+    {{ block.title }}
+  </div>
+  <div class="candidate-table-row__bio font-condensed">
+    {% if block.age %}{{ block.age }} let,{% endif %}
+    {% if block.job %}{{ block.job }},{% endif %}
+    {% if block.city %}{{ block.city }}{% endif %}
+  </div>
+  <div class="candidate-table-row__affiliation">
+    <div class="flex items-center">
+      {% if block.is_pirate %}
+        <div class="avatar w-6 mr-2">
+          <img src="{% static "shared/img/logo_black.svg" %}" alt="Pirátská strana">
+        </div>
+        <span class="font-bold font-condensed">Pirátská strana</span>
+      {% endif %}
+
+      {% if not block.is_pirate and block.other_party %}
+        {% if block.other_party_logo %}
+          {% image block.other_party_logo width-48 as logo_img %}
+          <div class="avatar w-6 mr-2">
+            <img src="{{ logo_img.url }}" alt="{{ block.other_party }}">
+          </div>
+        {% endif %}
+
+        <span class="font-bold font-condensed">{{ block.other_party }}</span>
+      {% endif %}
+    </div>
+  </div>
+</div>
diff --git a/shared/templates/shared/blocks/full_candidate_snippet_block.html b/shared/templates/shared/blocks/full_candidate_snippet_block.html
new file mode 100644
index 0000000000000000000000000000000000000000..cff979a858bcf07167de173a87e874cc37f5ab51
--- /dev/null
+++ b/shared/templates/shared/blocks/full_candidate_snippet_block.html
@@ -0,0 +1,94 @@
+{% load static wagtailimages_tags %}
+
+<div class="candidate-card container-padding--zero sm:container-padding--auto ">
+  <div
+    class="candidate-card__wrapper candidate-card__wrapper sm:candidate-card-list__item-wrapper md:candidate-card-list__item-wrapper--border"
+  >
+    <div class="card candidate-card__body elevation-0 hover:elevation-10 transition duration-200">
+      <div class="candidate-card__avatar">
+        <div class="candidate-card__position">
+          {{ forloop.counter }}
+        </div>
+          <div class="avatar avatar--sm sm:avatar--lg">
+              {% if block.profile_photo %}
+                  {# Match sizing of person page to keep the image version count low #}
+                  {% image block.profile_photo fill-416x416 as profile_img %}
+                  <img src="{{ profile_img.url }}" alt="{{ block.title }}"/>
+              {% else %}
+                  <img src="{% static "shared/img/unknown_pirate_416x416.jpg" %}" alt="{{ block.title }}"/>
+              {% endif %}
+          </div>
+      </div>
+      <div class="candidate-card__bio">
+        <h1 class="head-heavy-xs">
+            {{ block.title }}
+        </h1>
+        {% if block.email %}
+          <a href="mailto:{{ block.email }}" class="block candidate-card__bio-item mb-4">
+            {{ block.email }}
+          </a>
+        {% endif %}
+        {% if block.job %}
+          <h2 class=" candidate-card__bio-item">
+            {{ block.job }}
+          </h2>
+        {% endif %}1
+        {% if block.city %}
+          <h2 class="head-allcaps-4xs mt-4">
+            {{ block.city }}
+          </h2>
+        {% endif %}
+      </div>
+      <div class="candidate-card__affiliation">
+        {% if block.age %}<div>{{ block.age }} let</div>{% endif %}
+        <div class="flex items-center">
+          {% if block.is_pirate %}
+            <div class="avatar w-6 mr-2">
+              <img src="{% static "shared/img/logo_black.svg" %}" alt="Pirátská strana">
+            </div>
+            <span class="font-bold font-condensed">Pirátská strana</span>
+          {% endif %}
+
+          {% if not block.is_pirate and block.other_party %}
+            {% if block.other_party_logo %}
+              {% image block.other_party_logo width-48 as logo_img %}
+              <div class="avatar w-6 mr-2">
+                <img src="{{ logo_img.url }}" alt="{{ block.other_party }}">
+              </div>
+            {% endif %}
+
+            <span class="font-bold font-condensed">{{ block.other_party }}</span>
+          {% endif %}
+        </div>
+      </div>
+      <div class="card__body candidate-card__social">
+        <div class="social-icon-group space-x-2">
+          {% if block.facebook_url %}
+            <a href="{{ block.facebook_url }}" target="_blank" class="social-icon" rel="noreferrer noopener">
+              <i class="ico--facebook"></i>
+            </a>
+          {% endif %}
+          {% if block.instagram_url %}
+            <a href="{{ block.instagram_url }}" target="_blank" class="social-icon" rel="noreferrer noopener">
+              <i class="ico--instagram"></i></a>
+          {% endif %}
+          {% if block.twitter_url %}
+            <a href="{{ block.twitter_url }}" target="_blank" class="social-icon" rel="noreferrer noopener">
+              <i class="ico--twitter"></i>
+            </a>
+          {% endif %}
+          {% if block.youtube_url %}
+            <a href="{{ block.youtube_url }}" target="_blank" class="social-icon" rel="noreferrer noopener">
+              <i class="ico--youtube"></i>
+            </a>
+          {% endif %}
+          {% if block.flickr_url %}
+            <a href="{{ block.flickr_url }}" target="_blank" class="social-icon" rel="noreferrer noopener">
+              <i class="ico--flickr"></i>
+            </a>
+          {% endif %}
+        </div>
+      </div>
+    </div>
+  </div>
+</div>