diff --git a/frontend/src/main.less b/frontend/src/main.less
index 331d6ede0dbbc3e23f931292c08cc9bb6292236e..89c0e5389c3cf04c199ab00d8964d84ca7b59c06 100644
--- a/frontend/src/main.less
+++ b/frontend/src/main.less
@@ -128,7 +128,7 @@ main {
 }
 
 .preview {
-	width: 95vw;
+	width: min(95vw, 100rem);
 	/* A4 aspect ratio: √2:1 */
 	aspect-ratio: 1.4142135623730951;
 
@@ -143,3 +143,68 @@ main {
 .preview-label {
 	place-self: center;
 }
+
+form {
+	display: inline-block;
+}
+
+@label-padding: 90px;
+
+label.for-text {
+	display: inline-block;
+	min-width: @label-padding;
+	text-align: right;
+}
+
+input[type="text"], textarea {
+	width: 300px;
+}
+
+textarea {
+	height: 5em;
+	vertical-align: top;
+}
+
+fieldset {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+fieldset > div {
+	display: flex;
+	gap: 0.5rem;
+	flex-direction: column;
+}
+
+.imageselect > div {
+	width: 10rem;
+	display: flex;
+	gap: 0.5rem;
+}
+
+fieldset label {
+	flex-grow: 1;
+}
+
+.imageselect img {
+	width: 100%;
+	background-color: #fff;
+}
+
+fieldset input {
+	display: none;
+}
+
+fieldset img,
+fieldset iframe,
+.preview-small {
+	border: 3px solid lightgray;
+	border-radius: 10px;
+}
+
+input[type="radio"]:checked {
+	& + label > img,
+	& + iframe {
+		border:3px solid red;
+	}
+}
diff --git a/pdm.lock b/pdm.lock
index e3ff23dde2226475d84796e9a83b8f5e683edfc4..0a80dc942e57abdc36bdb4f5399d2475c8830a99 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -5,7 +5,7 @@
 groups = ["default", "dev"]
 strategy = ["inherit_metadata"]
 lock_version = "4.5.0"
-content_hash = "sha256:4254d9a7fba04b352e6ddf4d85e4ce62abbf60c4d39127493dd18cb4b4dbc110"
+content_hash = "sha256:618addcae7a6ab39fb74f18ca29c1a64f762aea504459d0db220bc7e886efe59"
 
 [[metadata.targets]]
 requires_python = ">=3.12"
@@ -1304,21 +1304,6 @@ files = [
     {file = "wtforms-3.1.2.tar.gz", hash = "sha256:f8d76180d7239c94c6322f7990ae1216dae3659b7aa1cee94b6318bdffb474b9"},
 ]
 
-[[package]]
-name = "wtforms-sqlalchemy"
-version = "0.4.1"
-requires_python = ">=3.8"
-summary = "SQLAlchemy tools for WTForms"
-groups = ["default"]
-dependencies = [
-    "SQLAlchemy>=1.4",
-    "WTForms>=3.1",
-]
-files = [
-    {file = "WTForms-SQLAlchemy-0.4.1.tar.gz", hash = "sha256:370f52b738527cf6d8ab78d3488afb9342666144da2637e0cf8b5ae522e8a4db"},
-    {file = "WTForms_SQLAlchemy-0.4.1-py3-none-any.whl", hash = "sha256:df3965015b60de172f4b35e691a47d9913d56bb0abb62c620edd04c1376979e3"},
-]
-
 [[package]]
 name = "zopfli"
 version = "0.2.3"
diff --git a/pyproject.toml b/pyproject.toml
index d42a50e688a88a5d8f4a1b9b961bc0e259786069..a325737ae3b34ea2ab9bd0af60dce42b99a75949 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,7 +15,6 @@ dependencies = [
     "flask",
     "flask-sqlalchemy",
     "flask-wtf",
-    "wtforms-sqlalchemy",
     "uuid7",
     "psycopg",
     "flask-weasyprint",
diff --git a/schilder2000/instance.py b/schilder2000/instance.py
index adef3a19e93bfff48be7c9340a74ff94a31734d6..d869e36189cc8e98a29662e169dc494bb9dc837f 100644
--- a/schilder2000/instance.py
+++ b/schilder2000/instance.py
@@ -2,6 +2,8 @@ from . import db
 from .models import Schild
 from .helpers import Blueprint, get_template_attribute
 
+from collections import namedtuple
+from pathlib import Path
 
 from flask import url_for
 
@@ -19,7 +21,6 @@ bp = Blueprint(
 @bp.route("/schild/<ident>.html")
 def schild_html(ident):
     schild = db.get_or_404(Schild, ident)
-    # raise Exception
     return bp.render_template(schild.template, schild=schild)
 
 
@@ -38,13 +39,16 @@ def sample_pdf(template):
     return render_pdf(url_for(".sample_html", template=template))
 
 
+Template = namedtuple("Template", "name description")
+
+
 def list_templates():
     schild = Schild()
     loader = bp.jinja_loader
     for t in loader.list_templates():
         if t.startswith("_"):
             continue
-        yield dict(
+        yield Template(
             name=t,
             description=get_template_attribute(
                 bp.real_template_name(t),
@@ -53,3 +57,9 @@ def list_templates():
                 default=None,
             ),
         )
+
+
+def list_images():
+    base = Path(bp.static_folder) / "img"
+    for f in base.iterdir():
+        yield f.name
diff --git a/schilder2000/models.py b/schilder2000/models.py
index 2c82aa503573a388dd5d1c886ad275562260d194..322f0fd3a225dd083fa2e1e13ed6c642c2c54015 100644
--- a/schilder2000/models.py
+++ b/schilder2000/models.py
@@ -5,6 +5,10 @@ from uuid_extensions import uuid7
 from sqlalchemy import String, Text, Uuid
 from sqlalchemy.orm import Mapped, mapped_column
 
+from flask_wtf import FlaskForm
+
+from wtforms import fields, validators
+
 from . import db
 
 
@@ -14,3 +18,25 @@ class Schild(db.Model):
     text: Mapped[str] = mapped_column(Text)
     image: Mapped[str] = mapped_column(String(255), nullable=True)
     template: Mapped[str] = mapped_column(String(255))
+
+
+class SchildForm(FlaskForm):
+    title = fields.StringField(
+        "Titel",
+        validators=[
+            validators.InputRequired(),
+            validators.Length(max=Schild.title.type.length),
+        ],
+    )
+    text = fields.TextAreaField(
+        "Text",
+        validators=[validators.InputRequired()],
+    )
+    image = fields.RadioField(
+        "Bild",
+        validators=[validators.Optional()],
+    )
+    template = fields.RadioField(
+        "Vorlage",
+        validators=[validators.DataRequired()],
+    )
diff --git a/schilder2000/templates/schild.html.j2 b/schilder2000/templates/schild.html.j2
index ceea6134c00880dc6b23d3d4d4416a8cee011692..c6a1008f84876fe739894af2e1b95216fc11eb96 100644
--- a/schilder2000/templates/schild.html.j2
+++ b/schilder2000/templates/schild.html.j2
@@ -5,7 +5,7 @@
 		{{ field }}
 	{%- else -%}
 		<div class="box">
-			{{ field.label }}
+			{{ field.label(class="for-text") }}
 			{{ field(class="input-dispatch") }}
 		</div>
 	{%- endif -%}
@@ -21,16 +21,57 @@
 
 {% block main -%}
 	<form method="post" action="">
-		{%- for field in form -%}
-			{{ render_field(field) }}
-		{%- endfor -%}
-		<select name="template">
-			{%- for t in templates -%}
-				<option value="{{ t.name }}">
-					{{ t.description or t.name }}
-				</option>
+		{{ form.csrf_token }}
+
+		{{ render_field(form.title) }}
+		{{ render_field(form.text) }}
+
+		<fieldset class="templateselect">
+			<legend>Vorlage</legend>
+			{%- for t in form.template.choices -%}
+				<div>
+					<input
+						type="radio"
+						name="template"
+						id="template:{{ t.name }}"
+						value="{{ t.name }}"
+						{% if t.name == (schild | default(None)).template -%}
+							checked
+						{%- endif -%}
+					/>
+					<iframe
+						class="preview preview-small"
+						src="{{ url_for('instance.sample_html', template=t.name) }}"
+						id="template-preview:{{ t.name }}"
+					>
+					</iframe>
+					<label for="template:{{ t.name }}" class="preview-label">
+						{{ t.description or t.name }}
+					</label>
+				</div>
 			{% endfor %}
-		</select>
+		</fieldset>
+
+		<fieldset class="imageselect">
+			<legend>Bild</legend>
+			{%- for img in form.image.choices -%}
+				<div>
+					<input
+						type="radio"
+						name="image"
+						id="img:{{ img }}"
+						value="{{ img }}"
+						{% if img == (schild | default(None)).image -%}
+							checked
+						{%- endif -%}
+					/>
+					<label for="img:{{ img }}">
+						<img src="{{ url_for('instance.static', filename='img/'+img) }}" title="{{ img }}" />
+					</label>
+				</div>
+			{%- endfor -%}
+		</fieldset>
+
 		<div class="box">
 			{%- if schild -%}
 				<input type="submit" value="Speichern" />
@@ -44,6 +85,7 @@
 			{%- endif -%}
 		</div>
 	</form>
+
 	{%- if schild %}
 		<div>
 			<a href="{{ url_for('instance.schild_pdf', ident=schild.ident) }}">
@@ -56,7 +98,8 @@
 				<iframe
 					class="preview"
 					id="preview"
-					src="{{ url_for('instance.schild_html', ident=schild.ident) }}" />
+					src="{{ url_for('instance.schild_html', ident=schild.ident) }}">
+				</iframe>
 			</div>
 		</div>
 	{% endif %}
diff --git a/schilder2000/views.py b/schilder2000/views.py
index 953afa3b75507e1ae6dc82e3d89da1c9787548ca..935e4d9f276c9ed7f7be30eb74a933dc54017b73 100644
--- a/schilder2000/views.py
+++ b/schilder2000/views.py
@@ -1,49 +1,49 @@
 from . import db
-from .instance import list_templates
-from .models import Schild
+from .instance import list_templates, list_images
+from .models import Schild, SchildForm
 
 from flask import Blueprint, render_template, request, redirect, url_for
 
-from flask_wtf import FlaskForm
-
-from wtforms_sqlalchemy.orm import model_form
 
 bp = Blueprint("views", __name__)
 
 
-SchildForm = model_form(Schild, base_class=FlaskForm)
-
-
 @bp.route("/")
 def index():
     schilder = db.session.execute(db.select(Schild)).scalars()
     return render_template("index.html.j2", schilder=schilder)
 
 
+def _do_schild_form(schild):
+    form = SchildForm(request.form, obj=schild)
+    form.image.choices = list(list_images())
+    form.template.choices = list(list_templates())
+    if request.method == "POST" and form.validate():
+        form.populate_obj(schild)
+        db.session.add(schild)
+        db.session.commit()
+    return form
+
+
 @bp.route("/schild/<ident>", methods=["GET", "POST"])
 def schild(ident):
     schild = db.get_or_404(Schild, ident)
-    if request.method == "POST":
-        form = SchildForm(request.form, obj=schild)
-        if form.validate():
-            form.populate_obj(schild)
-            db.session.add(schild)
-            db.session.commit()
-    else:
-        form = SchildForm(obj=schild)
-    return render_template("schild.html.j2", schild=schild, form=form, templates=list_templates())
+    form = _do_schild_form(schild)
+    return render_template(
+        "schild.html.j2",
+        schild=schild,
+        form=form,
+    )
 
 
 @bp.route("/create", methods=["GET", "POST"])
 def create():
     schild = Schild()
+    form = _do_schild_form(schild)
     if request.method == "POST":
-        form = SchildForm(request.form, obj=schild)
-        if form.validate():
-            form.populate_obj(schild)
-            db.session.add(schild)
-            db.session.commit()
-            return redirect(url_for(".schild", ident=schild.ident))
+        return redirect(url_for(".schild", ident=schild.ident))
     else:
-        form = SchildForm(obj=schild)
-    return render_template("schild.html.j2", form=form)
+        return render_template(
+            "schild.html.j2",
+            form=form,
+        )