diff --git a/opentech/apply/funds/edit_handlers.py b/opentech/apply/funds/edit_handlers.py
index 5b89c032b384e03bcf6efb42b99ef17cb096c5e6..06a307c52fc0d15e4d76136079b54e9ce52e6f7b 100644
--- a/opentech/apply/funds/edit_handlers.py
+++ b/opentech/apply/funds/edit_handlers.py
@@ -1,4 +1,4 @@
-from django.forms import Field
+from django.forms import Field, Widget
 from django.forms.utils import pretty_name
 from django.urls import reverse
 from django.template.loader import render_to_string
@@ -8,9 +8,34 @@ from wagtail.wagtailcore.models import Page
 from wagtail.wagtailadmin.edit_handlers import BaseFieldPanel, EditHandler, FieldPanel
 
 
+def reverse_edit(obj):
+    if isinstance(obj, Page):
+        return reverse('wagtailadmin_pages:edit', args=(obj.id,))
+
+    url_name = f'{obj._meta.app_label}_{obj._meta.model_name}_modeladmin_edit'
+    return reverse(url_name, args=(obj.id,))
+
+
+class ReadonlyWidget(Widget):
+    template_name = 'funds/admin/widgets/read_only.html'
+
+    def format_value(self, value):
+        self.value = value
+        return super().format_value(value)
+
+    def get_context(self, *args, **kwargs):
+        context = super().get_context(*args, **kwargs)
+        try:
+            edit_link = reverse_edit(self.value.form)
+        except AttributeError:
+            pass
+        else:
+            context['widget']['edit_link'] = edit_link
+        return context
+
+
 class DisplayField(Field):
-    pass
-    # widget =
+    widget = ReadonlyWidget
 
 
 class BaseReadOnlyPanel(EditHandler):
@@ -18,10 +43,12 @@ class BaseReadOnlyPanel(EditHandler):
     field_template = 'wagtailadmin/shared/field.html'
 
     def context(self):
+        context = {}
+
         try:
             value = getattr(self.instance, self.attr)
         except AttributeError:
-            self.attr = str(self.instance)
+            self.attr = '__'.join([self.instance._meta.model_name, str(self.instance.id)])
             value = self.instance
 
         if callable(value):
@@ -29,10 +56,12 @@ class BaseReadOnlyPanel(EditHandler):
 
         self.form.initial[self.attr] = value
         self.bound_field = DisplayField().get_bound_field(self.form, self.attr)
-        return {
-            'self': self,
-            'field': self.bound_field,
-        }
+        context.update(
+            self=self,
+            field=self.bound_field,
+            show_label=False,
+        )
+        return context
 
     def render_as_object(self):
         return render_to_string(self.template, self.context())
@@ -56,14 +85,6 @@ class ReadOnlyPanel:
         return type(str(_('ReadOnlyPanel')), (BaseReadOnlyPanel,), kwargs)
 
 
-def reverse_edit(obj):
-    if isinstance(obj, Page):
-        return reverse('wagtailadmin_pages:edit', args=(obj.id,))
-
-    url_name = f'{obj._meta.app_label}_{obj._meta.model_name}_modeladmin_edit'
-    return reverse(url_name, args=(obj.id,))
-
-
 class BaseReadOnlyInlinePanel(BaseReadOnlyPanel):
     template = 'wagtailadmin/edit_handlers/multi_field_panel.html'
 
diff --git a/opentech/apply/funds/templates/funds/admin/widgets/read_only.html b/opentech/apply/funds/templates/funds/admin/widgets/read_only.html
new file mode 100644
index 0000000000000000000000000000000000000000..a01651f39d13270a87efcea09d8815f8b2b60b15
--- /dev/null
+++ b/opentech/apply/funds/templates/funds/admin/widgets/read_only.html
@@ -0,0 +1 @@
+<div class="col8">{{ widget.value }}</div>{% if widget.edit_link %}<div class="col4"><a class="button button-small" href="{{ widget.edit_link }}">Edit</a></div>{% endif %}