From e84d73024a7e2ec89a15e728ef64be247d42df65 Mon Sep 17 00:00:00 2001
From: Ioannis Igoumenos <ioigoume@gmail.com>
Date: Tue, 30 Apr 2024 17:03:11 +0300
Subject: [PATCH] CFM-291-refactor_form_code_structuring (#187)

* Decouple markup from FieldHelper.Move to elements.

* CoSettings

* ApiUsers fields-generate.inc

* Cos

* Addresses

* EmailAddresses

* Groups

* Urls, Types, Servers

* Identifiers,HistoryRecords,TelephoneNumbers,Names,AdHocAttributes,PersonRoles

* ExternalIdentities,ExternalIdentityRoles,ExternalIdentitySources

* ExternalIdentitySourceRecords,IdentifierAssignments

* fixes

* update FieeldHelper

* Jobs

* JobHistoryRecords

* CoreAssigne, CoreServer

* Pronouns,ProvisioningTargets,ProvisioningHistoryRecords

* ProvisioningHistoryRecords

* People

* Pipelines

* Jobs

* GroupNestings

* GroupMembers

* rename field parameters. Added prefix field.

* Available plugins.Alert to element.

* required field fix for nameDiv and infoDiv. Take fieldOptions into consideration.

* cleanup

* Add frozen and plugin configuration handling

* remove temp helper files

* minor improvements

* FieldHelper improvements

* SmtpServers, MessageTemplates, Notifications

* revert FileProvisioner change

* fix alert css classes calculation

* fix review errors
---
 .../src/Model/Table/ApiSourcesTable.php       |   6 +-
 .../templates/ApiSources/fields.inc           |  11 +-
 .../src/Model/Table/FileSourcesTable.php      |   4 +-
 .../templates/FileProvisioners/fields.inc     |   6 +-
 .../templates/FileSources/fields.inc          |  22 +-
 .../templates/SqlProvisioners/fields.inc      |  17 +-
 app/config/.env.example                       |   2 +
 app/config/app.php                            |  11 +
 .../templates/FormatAssigners/fields.inc      |  34 +-
 .../templates/SqlAssigners/fields.inc         |  16 +-
 .../templates/SmtpServers/fields.inc          |  49 +-
 .../templates/SqlServers/fields.inc           |  25 +-
 app/src/Controller/ApiUsersController.php     |   3 +-
 app/src/Controller/StandardController.php     |   4 +-
 app/src/Model/Table/AdHocAttributesTable.php  |   3 +-
 app/src/Model/Table/HistoryRecordsTable.php   |   3 +-
 app/src/View/Helper/AlertHelper.php           |  72 +-
 app/src/View/Helper/FieldHelper.php           | 910 +++++-------------
 app/templates/AdHocAttributes/fields.inc      |  23 +-
 app/templates/Addresses/fields.inc            |  54 +-
 app/templates/ApiUsers/fields-generate.inc    |  16 +-
 app/templates/ApiUsers/fields.inc             |  73 +-
 app/templates/CoSettings/fields.inc           | 129 ++-
 app/templates/Cos/fields.inc                  |  17 +-
 app/templates/Cos/select.php                  |   2 +-
 app/templates/Cous/fields.inc                 |  16 +-
 app/templates/Dashboards/configuration.php    |   6 +-
 app/templates/Dashboards/search.php           |   4 +-
 app/templates/EmailAddresses/fields.inc       |  40 +-
 .../ExtIdentitySourceRecords/fields.inc       |  24 +-
 app/templates/ExternalIdentities/fields.inc   |  22 +-
 .../ExternalIdentityRoles/fields-nav.inc      |   2 +-
 .../ExternalIdentityRoles/fields.inc          |  67 +-
 .../ExternalIdentitySources/fields.inc        |  29 +-
 .../ExternalIdentitySources/retrieve.php      |   3 +-
 .../ExternalIdentitySources/search.php        |   5 +-
 app/templates/GroupMembers/fields.inc         |  74 +-
 app/templates/GroupNestings/fields.inc        |  51 +-
 app/templates/Groups/fields.inc               |  75 +-
 app/templates/HistoryRecords/fields.inc       | 103 +-
 .../IdentifierAssignments/fields.inc          |  83 +-
 app/templates/Identifiers/fields.inc          |  39 +-
 app/templates/JobHistoryRecords/fields.inc    |  49 +-
 app/templates/Jobs/fields.inc                 | 123 ++-
 app/templates/MessageTemplates/fields.inc     |  36 +-
 app/templates/Names/fields.inc                |  46 +-
 app/templates/Notifications/fields.inc        | 177 ++--
 app/templates/People/fields.inc               |  40 +-
 app/templates/PersonRoles/fields.inc          |  82 +-
 app/templates/Pipelines/fields.inc            |  63 +-
 app/templates/Pronouns/fields.inc             |  31 +-
 .../ProvisioningHistoryRecords/fields.inc     |  66 +-
 app/templates/ProvisioningTargets/fields.inc  |  55 +-
 app/templates/ProvisioningTargets/status.php  |   4 +-
 app/templates/Servers/fields.inc              |  13 +-
 app/templates/Standard/add-edit-view.php      |  57 +-
 app/templates/TelephoneNumbers/fields.inc     |  34 +-
 app/templates/Types/fields.inc                |  32 +-
 app/templates/Urls/fields.inc                 |  31 +-
 .../element/filter/dateTimeFilters.php        |   4 +-
 app/templates/element/filter/filter.php       |   2 +-
 app/templates/element/flash.php               |   4 +-
 app/templates/element/flash/default.php       |   2 +-
 app/templates/element/flash/error.php         |   6 +-
 app/templates/element/flash/information.php   |   6 +-
 app/templates/element/flash/success.php       |   6 +-
 app/templates/element/form/entityID.php       |  37 +
 app/templates/element/form/fieldDiv.php       |  56 ++
 .../element/form/infoDiv/autocomplete.php     |  59 ++
 app/templates/element/form/infoDiv/check.php  |  55 ++
 .../element/form/infoDiv/default.php          |  33 +
 .../element/form/infoDiv/groupMember.php      |  41 +
 .../element/form/infoDiv/grouped.php          |  51 +
 app/templates/element/form/infoDiv/source.php |  35 +
 app/templates/element/form/infoDiv/status.php |  67 ++
 .../element/form/infoDiv/withPrefix.php       |  38 +
 app/templates/element/form/listItem.php       | 106 ++
 app/templates/element/form/nameDiv.php        | 106 ++
 app/templates/element/form/notSetDiv.php      |  32 +
 app/templates/element/form/requiredSpan.php   |  33 +
 app/templates/element/form/submit.php         |  43 +
 app/templates/element/form/unorderedList.php  |  64 ++
 app/templates/element/menuPanel.php           |   6 +-
 app/templates/element/mveaJs.php              |  50 +-
 app/templates/element/notify/alert.php        |  66 ++
 app/templates/element/notify/banner.php       |  39 +
 app/templates/element/notify/closeButton.php  |  35 +
 app/templates/element/peopleAutocomplete.php  |  18 +-
 app/templates/layout/default.php              |   6 +-
 app/templates/layout/iframe.php               |   4 +-
 app/webroot/js/comanage/comanage.js           |   2 +-
 91 files changed, 2677 insertions(+), 1529 deletions(-)
 create mode 100644 app/templates/element/form/entityID.php
 create mode 100644 app/templates/element/form/fieldDiv.php
 create mode 100644 app/templates/element/form/infoDiv/autocomplete.php
 create mode 100644 app/templates/element/form/infoDiv/check.php
 create mode 100644 app/templates/element/form/infoDiv/default.php
 create mode 100644 app/templates/element/form/infoDiv/groupMember.php
 create mode 100644 app/templates/element/form/infoDiv/grouped.php
 create mode 100644 app/templates/element/form/infoDiv/source.php
 create mode 100644 app/templates/element/form/infoDiv/status.php
 create mode 100644 app/templates/element/form/infoDiv/withPrefix.php
 create mode 100644 app/templates/element/form/listItem.php
 create mode 100644 app/templates/element/form/nameDiv.php
 create mode 100644 app/templates/element/form/notSetDiv.php
 create mode 100644 app/templates/element/form/requiredSpan.php
 create mode 100644 app/templates/element/form/submit.php
 create mode 100644 app/templates/element/form/unorderedList.php
 create mode 100644 app/templates/element/notify/alert.php
 create mode 100644 app/templates/element/notify/banner.php
 create mode 100644 app/templates/element/notify/closeButton.php

diff --git a/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php b/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php
index fd4b255e4..cf4fd5866 100644
--- a/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php
+++ b/app/availableplugins/ApiConnector/src/Model/Table/ApiSourcesTable.php
@@ -189,7 +189,7 @@ protected function mapApiToRegistry(string $model, array $attributes): array {
    */
 
   public function remove(
-    \App\Model\Entity\ExternalIdentitySource $source, 
+    \App\Model\Entity\ExternalIdentitySource $source,
     string $sorId
   ): array {
     // We call this remove() so as not to interfere with the default table::delete().
@@ -293,7 +293,7 @@ protected function resultToEntityData(array $result): array {
    */
 
   public function retrieve(
-    \App\Model\Entity\ExternalIdentitySource $source, 
+    \App\Model\Entity\ExternalIdentitySource $source,
     string $source_key
   ): array {
     $ret = [
@@ -328,7 +328,7 @@ public function retrieve(
    */
 
   public function search(
-    \App\Model\Entity\ExternalIdentitySource $source, 
+    \App\Model\Entity\ExternalIdentitySource $source,
     array $searchAttrs
   ): array {
     $ret = [];
diff --git a/app/availableplugins/ApiConnector/templates/ApiSources/fields.inc b/app/availableplugins/ApiConnector/templates/ApiSources/fields.inc
index 6eb871263..8bd3e6ec6 100644
--- a/app/availableplugins/ApiConnector/templates/ApiSources/fields.inc
+++ b/app/availableplugins/ApiConnector/templates/ApiSources/fields.inc
@@ -30,8 +30,15 @@ if($vv_action == 'add' || $vv_action == 'edit') {
   
   print '<li class="info-title"><h3>' . __d('api_connector', 'field.ApiSources.push_mode') . '</h3></li>';
 
-  print $this->Field->banner(__d('api_connector', 'information.endpoint.push', [$vv_push_endpoint]));
+  print $this->element('banner', [
+    'info' => __d('api_connector', 'information.endpoint.push', [$vv_push_endpoint])
+  ]);
 
-  print $this->Field->control('api_user_id');
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'api_user_id',
+    ]
+  ]);
   
 }
diff --git a/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php b/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php
index c170e3ebb..82be14a59 100644
--- a/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php
+++ b/app/availableplugins/FileConnector/src/Model/Table/FileSourcesTable.php
@@ -349,7 +349,7 @@ protected function resultToEntityData(array $result): array {
    */
 
   public function retrieve(
-    \App\Model\Entity\ExternalIdentitySource $source, 
+    \App\Model\Entity\ExternalIdentitySource $source,
     string $source_key
   ): array {
     // Read the field configuration (for resultToEntity)
@@ -423,7 +423,7 @@ public function ruleIsFileReadable($entity, array $options): string|bool {
    */
 
   public function search(
-    \App\Model\Entity\ExternalIdentitySource $source, 
+    \App\Model\Entity\ExternalIdentitySource $source,
     array $searchAttrs
   ): array {
     // Read the field configuration (for resultToEntity)
diff --git a/app/availableplugins/FileConnector/templates/FileProvisioners/fields.inc b/app/availableplugins/FileConnector/templates/FileProvisioners/fields.inc
index 4980a687a..d5e5c8353 100644
--- a/app/availableplugins/FileConnector/templates/FileProvisioners/fields.inc
+++ b/app/availableplugins/FileConnector/templates/FileProvisioners/fields.inc
@@ -27,5 +27,9 @@
 
 // This view does currently not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('filename');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'filename',
+    ]
+  ]);
 }
diff --git a/app/availableplugins/FileConnector/templates/FileSources/fields.inc b/app/availableplugins/FileConnector/templates/FileSources/fields.inc
index 2380fe7bb..e9e7ae621 100644
--- a/app/availableplugins/FileConnector/templates/FileSources/fields.inc
+++ b/app/availableplugins/FileConnector/templates/FileSources/fields.inc
@@ -27,13 +27,17 @@
 
 // This view does currently not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('filename');
-
-  print $this->Field->control('format');
-
-  print $this->Field->control('archivedir');
-
-  print $this->Field->control('threshold_warn');
-
-  print $this->Field->control('threshold_override');
+  foreach([
+            'filename',
+            'format',
+            'archivedir',
+            'threshold_warn',
+            'threshold_override',
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 }
diff --git a/app/availableplugins/SqlConnector/templates/SqlProvisioners/fields.inc b/app/availableplugins/SqlConnector/templates/SqlProvisioners/fields.inc
index 2b23c2634..ff3da2816 100644
--- a/app/availableplugins/SqlConnector/templates/SqlProvisioners/fields.inc
+++ b/app/availableplugins/SqlConnector/templates/SqlProvisioners/fields.inc
@@ -27,7 +27,18 @@
 
 // This view does currently not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('server_id');
-  
-  print $this->Field->control('table_prefix', ['default' => 'sp_']);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'server_id',
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'table_prefix',
+      'options' => [
+        'default' => 'sp_'
+      ]
+    ]
+  ]);
 }
diff --git a/app/config/.env.example b/app/config/.env.example
index 15060f7be..f5ac424ce 100644
--- a/app/config/.env.example
+++ b/app/config/.env.example
@@ -25,6 +25,8 @@ export SECURITY_SALT="__SALT__"
 #export CACHE_DEFAULT_URL="file://tmp/cache/?prefix=${APP_NAME}_default&duration=${CACHE_DURATION}"
 #export CACHE_CAKECORE_URL="file://tmp/cache/persistent?prefix=${APP_NAME}_cake_core&serialize=true&duration=${CACHE_DURATION}"
 #export CACHE_CAKEMODEL_URL="file://tmp/cache/models?prefix=${APP_NAME}_cake_model&serialize=true&duration=${CACHE_DURATION}"
+#export CACHE_CAKEROUTE_URL="file://tmp/cache/routes?prefix=${APP_NAME}_cake_routes&serialize=true&duration=${CACHE_DURATION}"
+#export CACHE_HTMLELEMENT_URL="file://tmp/cache/elements?prefix=${APP_NAME}_html_elements&serialize=true&duration=${CACHE_DURATION}"
 
 # Uncomment these to define email transport configuration via environment variables.
 #export EMAIL_TRANSPORT_DEFAULT_URL=""
diff --git a/app/config/app.php b/app/config/app.php
index 8917343bd..58739ebd2 100644
--- a/app/config/app.php
+++ b/app/config/app.php
@@ -171,6 +171,17 @@
             'duration' => '+1 years',
             'url' => env('CACHE_CAKEROUTES_URL', null),
         ],
+      /**
+       * Configure the cache for html elements.
+       * Duration will be set to '+2 seconds' in bootstrap.php when debug = true
+       */
+        '_html_elements' => [
+          'className' => 'Cake\Cache\Engine\FileEngine',
+          'prefix' => 'myapp_cake_elements_',
+          'duration' => '+1 week',
+          'probability' => 100,
+          'url' => env('CACHE_HTMLELEMENT_URL', null),
+        ]
     ],
 
     /**
diff --git a/app/plugins/CoreAssigner/templates/FormatAssigners/fields.inc b/app/plugins/CoreAssigner/templates/FormatAssigners/fields.inc
index f382bc570..b6d06487a 100644
--- a/app/plugins/CoreAssigner/templates/FormatAssigners/fields.inc
+++ b/app/plugins/CoreAssigner/templates/FormatAssigners/fields.inc
@@ -47,18 +47,30 @@
 <?php
 // This view does currently not support read-only, and add is not used
 if($vv_action == 'edit') {
-  print $this->Field->control('format');
-  
-  print $this->Field->control(
-    fieldName: 'collision_mode',
-    options: [
-      'onChange' => 'updateGadgets()'
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'format'
     ]
-  );
-
-  print $this->Field->control('permitted_characters');
+  ]);
 
-  print $this->Field->control('minimum');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'collision_mode',
+      'options'   => [
+        'onChange' => 'updateGadgets()'
+      ]
+    ]
+  ]);
 
-  print $this->Field->control('maximum');
+  foreach([
+            'permitted_characters',
+            'minimum',
+            'maximum',
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 }
diff --git a/app/plugins/CoreAssigner/templates/SqlAssigners/fields.inc b/app/plugins/CoreAssigner/templates/SqlAssigners/fields.inc
index d0b2f5942..d2ede3a3d 100644
--- a/app/plugins/CoreAssigner/templates/SqlAssigners/fields.inc
+++ b/app/plugins/CoreAssigner/templates/SqlAssigners/fields.inc
@@ -27,9 +27,15 @@
 
 // This view does currently not support read-only, and add is not used
 if($vv_action == 'edit') {
-  print $this->Field->control('server_id');
-  
-  print $this->Field->control('source_table');
-
-  print $this->Field->control('type_id');
+  foreach([
+            'server_id',
+            'source_table',
+            'type_id',
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 }
diff --git a/app/plugins/CoreServer/templates/SmtpServers/fields.inc b/app/plugins/CoreServer/templates/SmtpServers/fields.inc
index b77ac9220..bac623cdc 100644
--- a/app/plugins/CoreServer/templates/SmtpServers/fields.inc
+++ b/app/plugins/CoreServer/templates/SmtpServers/fields.inc
@@ -27,19 +27,48 @@
 
 // This view does currently not support read-only, and add is not used
 if($vv_action == 'edit') {
-  print $this->Field->control('hostname');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'hostname',
+    ]
+  ]);
 
-  print $this->Field->control('port', ['default' => 587]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'port',
+      'fieldOptions' => [
+        'default' => 587
+      ]
+    ]]);
 
-  print $this->Field->control('username');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'username',
+    ]
+  ]);
 
-  print $this->Field->control('password');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'password',
+    ]
+  ]);
 
-  print $this->Field->control('use_tls', ['default' => true]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'use_tls',
+      'fieldOptions' => [
+        'default' => true
+      ]
+    ]]);
 
-  print $this->Field->control('default_from');
-
-  print $this->Field->control('default_reply_to');
-
-  print $this->Field->control('override_to');
+  foreach ([
+             'default_from',
+             'default_reply_to',
+             'override_to',
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
 }
diff --git a/app/plugins/CoreServer/templates/SqlServers/fields.inc b/app/plugins/CoreServer/templates/SqlServers/fields.inc
index 0d0a13d04..a15d291f9 100644
--- a/app/plugins/CoreServer/templates/SqlServers/fields.inc
+++ b/app/plugins/CoreServer/templates/SqlServers/fields.inc
@@ -27,15 +27,18 @@
 
 // This view does currently not support read-only, and add is not used
 if($vv_action == 'edit') {
-  print $this->Field->control('type');
-  
-  print $this->Field->control('hostname');
-
-  print $this->Field->control('port');
-
-  print $this->Field->control('databas');
-
-  print $this->Field->control('username');
-
-  print $this->Field->control('password');
+  foreach([
+            'type',
+            'hostname',
+            'port',
+            'databas',
+            'username',
+            'password',
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 }
diff --git a/app/src/Controller/ApiUsersController.php b/app/src/Controller/ApiUsersController.php
index 25a690757..aa871b09b 100644
--- a/app/src/Controller/ApiUsersController.php
+++ b/app/src/Controller/ApiUsersController.php
@@ -62,7 +62,8 @@ public function generate(string $id) {
                                                            'api.key',
                                                            $this->request->getParam('action'));
     $this->set('vv_title', $title);
-    
+
+    // Let the view render
     $this->render('/Standard/add-edit-view');
   }
 }
\ No newline at end of file
diff --git a/app/src/Controller/StandardController.php b/app/src/Controller/StandardController.php
index b1ee0a7d6..79085fed4 100644
--- a/app/src/Controller/StandardController.php
+++ b/app/src/Controller/StandardController.php
@@ -423,7 +423,7 @@ public function edit(string $id) {
     $this->set('vv_title', $title);
     $this->set('vv_supertitle', $supertitle);
     $this->set('vv_subtitle', $subtitle);
-    
+
     // Let the view render
     $this->render('/Standard/add-edit-view');
   }
@@ -870,7 +870,7 @@ public function view($id = null) {
     $this->set('vv_title', $title);
     $this->set('vv_supertitle', $supertitle);
     $this->set('vv_subtitle', $subtitle);
-    
+
     // Let the view render
     $this->render('/Standard/add-edit-view');
   }
diff --git a/app/src/Model/Table/AdHocAttributesTable.php b/app/src/Model/Table/AdHocAttributesTable.php
index 3bdb8a142..7822a3e0f 100644
--- a/app/src/Model/Table/AdHocAttributesTable.php
+++ b/app/src/Model/Table/AdHocAttributesTable.php
@@ -43,7 +43,8 @@ class AdHocAttributesTable extends Table {
   use \App\Lib\Traits\ValidationTrait;
   use \App\Lib\Traits\SearchFilterTrait;
   use \App\Lib\Traits\QueryModificationTrait;
-  
+  use \App\Lib\Traits\AutoViewVarsTrait;
+
   /**
    * Provide the default layout
    *
diff --git a/app/src/Model/Table/HistoryRecordsTable.php b/app/src/Model/Table/HistoryRecordsTable.php
index e3917a7d0..d37567c0f 100644
--- a/app/src/Model/Table/HistoryRecordsTable.php
+++ b/app/src/Model/Table/HistoryRecordsTable.php
@@ -41,7 +41,8 @@ class HistoryRecordsTable extends Table {
   use \App\Lib\Traits\TableMetaTrait;
   use \App\Lib\Traits\ValidationTrait;
   use \App\Lib\Traits\SearchFilterTrait;
-  
+  use \App\Lib\Traits\AutoViewVarsTrait;
+
   /**
    * Perform Cake Model initialization.
    *
diff --git a/app/src/View/Helper/AlertHelper.php b/app/src/View/Helper/AlertHelper.php
index d653759df..0c3d1ef68 100644
--- a/app/src/View/Helper/AlertHelper.php
+++ b/app/src/View/Helper/AlertHelper.php
@@ -32,65 +32,21 @@
 use \Cake\View\Helper;
 use phpDocumentor\Reflection\Types\Boolean;
 
-/**
- * Helper which will produce Bootstrap based alert
- *
- * @param string $message          Alert message
- * @param string $type             Define the type of Alert. The value should be one of
- *                                 [success,warning,danger,info]. Defaults to 'warning'
- * @param boolean $dismissable     Can the Alert be dismissed? Defaults to false.
- * @param string|null $title       Title to display (typically "Success", "Error", or "Warning"). Defaults to null.
- * @param boolean $dis_text_dark   Disable dark-text fonts for light|info color mode.
- * @return mixed - a constructed HTML block
- * @since  COmanage Registry v5.0.0
- */
 class AlertHelper extends Helper {
-  
-  public $helpers = ['Html'];
-  
-  public function alert(
-    string $message,
-    string $type = 'warning',
-    bool $dismissable = false,
-    string $title = null ) {
-    
-    $closeButton = '';
-    $dismissableClass = '';
-    if($dismissable) {
-      $closeButton = '
-        <span class="alert-button">
-          <button type="button" class="btn-close nospin" data-bs-dismiss="alert" aria-label="Close"></button>
-        </span>
-      ';
-      $dismissableClass = ' alert-dismissible';
-    }
-  
-    $titleMarkup = '';
-    if(!empty($title)) {
-      $titleMarkup = '<span class="alert-title-text">' . $title . '</span>';
-    }
-    
-    return '
-      <div class="alert alert-' . $type . $dismissableClass . ' co-alert" role="alert">
-        <div class="alert-body d-flex align-items-center">
-          <span class="alert-title d-flex align-items-center">
-            ' . $this->getAlertIcon($type) . $titleMarkup .  '
-          </span>
-          <span class="alert-message">        
-            ' . $message . '
-          </span>
-          ' . $closeButton . '
-        </div>
-      </div>
-    ';
-  }
-  
-  public function getAlertIcon(string $type) {
-    switch($type) {
-      case('success'): return '<span class="material-icons-outlined alert-icon">check_circle</span>';
-      case('information'): return '<span class="material-icons-outlined alert-icon">info</span>';
-      default: return '<span class="material-icons-outlined alert-icon">report_problem</span>';
-    }
+  /**
+   * Map Alert Type to Icon
+   *
+   * @param   string  $type
+   *
+   * @return string
+   */
+  public function getAlertIcon(string $type): string
+  {
+    return match($type) {
+      'success'     => 'check_circle',
+      'information' => 'info',
+      default       => 'report_problem'
+    };
   }
 
 }
\ No newline at end of file
diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php
index 1b26ac583..60355b63c 100644
--- a/app/src/View/Helper/FieldHelper.php
+++ b/app/src/View/Helper/FieldHelper.php
@@ -25,7 +25,6 @@
  * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
  */
 
-// XXX can we merge this with Match so we only maintain one file?
 declare(strict_types = 1);
 
 namespace App\View\Helper;
@@ -37,173 +36,155 @@
 use App\Lib\Util\StringUtilities;
 
 class FieldHelper extends Helper {
-  public $helpers = ['Form', 'Html', 'Url', 'Alert'];
-  
+  public $helpers = ['Form', 'Html'];
+
   // Is this read-only or read-write?
-  protected $editable = true;
+  protected bool $editable = true;
   
   // Our current model name
-  protected $modelName = null;
+  protected ?string $modelName = null;
   
   // The plugin we are rendering within, if set
-  protected $pluginName = null;
-  
+  protected ?string $pluginName = null;
+
   // The list of required fields
-  protected $reqFields = [];
-  
+  protected array $reqFields = [];
+
+  // The field types
+  protected array $fieldTypes = [];
+
   // The current entity, if edit or view
-  protected $entity = null;
+  protected ?object $entity = null;
 
   // The current action
-  protected $action = null;
+  protected ?string $action = null;
+
 
   /**
-   * Emit an informational banner.
+   * Constructor hook method.
+   *
+   * @param   array  $config The configuration settings provided to this helper.
    *
-   * @since  COmanage Registry v6.0.0
-   * @param  string $info Information string
-   * @return string       HTML for banner
+   * @return void
    */
-  
-  public function banner(string $info): string {
-    return '<li class="alert-banner">' .
-      $this->Alert->alert($info, 'warning')
-    . '</li>';
+  public function initialize(array $config): void
+  {
+    parent::initialize($config);
+
+    $this->reqFields = $this->getView()->get('vv_required_fields');
+    $this->modelName = $this->getView()->getName();
+    $this->action = $this->getView()->get('vv_action');
+    $this->editable = \in_array($this->action, ['add', 'edit']);
+    $this->pluginName = $this->getView()->getPlugin();
+    $this->entity = $this->getView()->get('vv_obj');
+    $this->fieldTypes = $this->getView()->get('vv_field_types');
   }
 
   /**
-   * Emit a form control.
+   * We autogenerate field labels and descriptions from the field name.
    *
-   * @param   string       $fieldName        Form field
-   * @param   array        $options          FormHelper control options
-   * @param   string|null  $labelText        Label text (fieldName language key used by default)
-   * @param   string|null  $ctrlCode         Control code passed in from wrapper functions
-   * @param   string       $cssClass         Start li css class passed in from wrapper functions
-   * @param   string       $beforeField      Markup to be placed before/above the field
-   * @param   string       $afterField       Markup to be placed after/below the field
-   * @param   string       $prefix           Field prefix - used for API Usernames
-   * @param   bool         $labelIsTextOnly  For fields that should not include <label> markup
-   * @param   string|null  $controlType
+   * @param   string  $fieldName
    *
-   * @return string  HTML for control
-   * @since  COmanage Registry v5.0.0
+   * @return array
    */
-  
-  public function control(string $fieldName,
-                          array  $options = [],
-                          string $labelText = null,
-                          string $ctrlCode = null,
-                          string $cssClass = '',
-                          string $beforeField = '',
-                          string $afterField = '',
-                          string $prefix = '',
-                          bool   $labelIsTextOnly = false,
-                          string $controlType = null): string {
-    // Specify a class on the <li> form control wrapper
-    $liClass = $cssClass;
-    // Get the field type from the map of fields (e.g. 'boolean', 'string', 'timestamp')
-    $fieldMap = $this->getView()->get('vv_field_types');
-    $fieldType = $controlType ?: $fieldMap[$fieldName];
+  public function calculateLabelAndDescription(string $fieldName): array
+  {
+    $desc = null;
+    $label = null;
 
-    // Generate the form control or pass along the markup generated in a wrapper function
-    $controlCode = $this->formControl($fieldName,
-                                      $options,
-                                      $labelText ,
-                                      $ctrlCode,
-                                      $prefix,
-                                      $controlType);
-    
-    $vv_obj = $this->getView()->get('vv_obj');
-
-    if($fieldName == 'plugin' && $this->action == 'edit') {
-      return $this->statusControl($fieldName, 
-                                  $vv_obj->$fieldName, 
-                                  [
-                                    'label' => __d('operation', 'configure.plugin'),
-                                    'url' => [
-                                      'plugin'      => null,
-                                      'controller'  => StringUtilities::entityToClassname($vv_obj),
-                                      'action'      => 'configure',
-                                      $vv_obj->id
-                                    ]
-                                  ], 
-                                  $labelText);
-    }
-    
-    // If an attribute is frozen, inject a special link to unfreeze it, since
-    // the attribute is read only and the admin can't simply uncheck the setting
-    if($fieldName == 'frozen' && $vv_obj->frozen) {
-      return $this->statusControl($fieldName, 
-                                  __d('field', 'frozen'), 
-                                  [
-                                    'label' => __d('operation', 'unfreeze'),
-                                    'url' => [
-                                      'plugin'      => null,
-                                      'controller'  => StringUtilities::entityToClassname($vv_obj),
-                                      'action'      => 'unfreeze',
-                                      $vv_obj->id
-                                    ]
-                                  ], 
-                                  $labelText);
-    }
+    // First, try to autogenerate the field label (if we weren't given one).
+    $pluginDomain = (!empty($this->getPluginName())
+      ? Inflector::underscore($this->getPluginName())
+      : null);
+
+    $modelName = $this->getModelName();
+    // We try to automagically determine if a description for the field exists by
+    // looking for the corresponding .desc language translation.
+    // We autogenerate field labels and descriptions from the field name.
+
+    // We loop over the field generation logic twice, first for a plugin
+    // context (if set) and then generally (if no plugin localization was found).
 
-    // Required fields are usually determined by the model validator, but for
-    // related models the view (currently) has to pass the field as required in
-    // $options. For fields of the form model.0.field, if $options['required']
-    // is true we'll update the set of required fields so the * renders correctly.
-    
-    if(isset($options['required'])
-       && $options['required']
-       && preg_match('/(\w+).(\d+).(\w+)/', $fieldName, $matches)) {
-      if(!in_array($matches[3], $this->reqFields)) {
-        $this->reqFields[] = $matches[3];
+    // We use $core as the variable for this loop, so the rest of the code
+    // is easier to read (!$core = plugin)
+    for($core = 0;$core < 2;$core++) {
+      if(!$core && empty($this->pluginName)) {
+        // No plugin set, go to the core field checks
+        continue;
+      }
+
+      // Is there a model specific key? For plugins, this will be in field.Model.Field
+
+      $key = (!$core ? 'field.' : '') . "$modelName.$fieldName";
+      $label = __d(($core ? 'field' : $pluginDomain), $key);
+
+      if($label === $key) {
+        // Model-specific label isn't found, try again for a general label
+
+        $f = null;
+
+        if(preg_match('/^(.*?)_id$/', $fieldName, $f)) {
+          // Map foreign keys (foo_id) to the controller label
+          $key = (!$core ? 'controller.' : '') . Inflector::camelize(Inflector::pluralize($f[1]));
+          $label = __d(($core ? 'controller' : $pluginDomain), $key, [1]);
+
+          if($key !== $label) {
+            break;
+          }
+        }
+
+        // Look up the key
+        $key = (!$core ? 'field.' : '') . $fieldName;
+        $label = __d(($core ? 'field' : $pluginDomain), $key);
+
+        if($key !== $label) {
+          break;
+        }
+      } else {
+        // If we found a key, break the loop
+        break;
       }
     }
-    
-    return $this->startLine($liClass)
-           . $this->formNameDiv($fieldName, $labelText, $fieldType, $labelIsTextOnly)
-           . ( !empty($prefix) ?
-                 $this->formInfoWithPrefixDiv($controlCode, $prefix, $beforeField, $afterField) :
-                 $this->formInfoDiv($controlCode, $beforeField, $afterField) )
-           . $this->endLine();
-  }
+    // We try to automagically determine if a description for the field exists by
+    // looking for the corresponding .desc language translation.
 
-  /**
-   * Emit a date/time form control.
-   * This is a wrapper function for $this->control()
-   *
-   * @param   string      $fieldName    Form field
-   * @param   string      $dateType     Standard, DateOnly, FromTime, ThroughTime
-   * @param   array|null  $queryParams  Request Query parameters used by the filtering Blocks to get the date values
-   *
-   * @return string  HTML for control
-   * @since  COmanage Registry v5.0.0
-   */
-  
-  public function dateControl(string $fieldName, string $dateType=DateTypeEnum::Standard, array $queryParams = null): string
-  {
-    $dateFieldConfig = $this->dateField($fieldName, $dateType, $queryParams);
-    return $this->control(fieldName:       $fieldName,
-                          options:         $dateFieldConfig['coptions'],
-                          ctrlCode:        $dateFieldConfig['controlCode'],
-                          cssClass:        $dateFieldConfig['cssClass'],
-                          labelIsTextOnly: $dateFieldConfig['labelIsTextOnly']);
+    for($core = 0;$core < 2;$core++) {
+      if(!$core && empty($this->pluginName)) {
+        // No plugin set, just go to the core field checks
+        continue;
+      }
+
+      $key = (!$core ? 'field.' : '') . "$modelName.$fieldName.desc";
+      $desc = __d(($core ? 'field' : $pluginDomain), $key);
+
+      // If the description is the literal key we just generated, there is no description
+      if($desc === $key) {
+        $desc = null;
+      } else {
+        break;
+      }
+    }
 
+    return [$label, $desc];
   }
 
   /**
    * Emit a date/time form control.
    * This is a wrapper function for $this->control()
    *
-   * @param   string      $fieldName    Form field
-   * @param   string      $dateType     Standard, DateOnly, FromTime, ThroughTime
-   * @param   array|null  $queryParams  Request Query parameters used by the filtering Blocks to get the date values
+   * @param   string       $fieldName    Form field
+   * @param   string       $dateType     Standard, DateOnly, FromTime, ThroughTime
+   * @param   array|null   $queryParams  Request Query parameters used by the filtering Blocks to get the date values
+   * @param   string|null  $label
    *
-   * @return array HTML for control
+   * @return string HTML element
    * @since  COmanage Registry v5.0.0
    */
 
-  public function dateField(string $fieldName, string $dateType=DateTypeEnum::Standard, array $queryParams = null): array
+  public function dateField(string $fieldName,
+                            string $dateType=DateTypeEnum::Standard,
+                            array $queryParams=null,
+                            string $label=null): string
   {
     // Initialize
     $dateFormat = $dateType === DateTypeEnum::DateOnly ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss';
@@ -231,18 +212,16 @@ public function dateField(string $fieldName, string $dateType=DateTypeEnum::Stan
     // ACTION VIEW
     if($this->action == 'view') {
       // return the date as plaintext
-      $controlCode = $this->notSetElement();
+      $element = $this->getView()->element('form/notSetDiv', [], [
+        'cache' => '_html_elements',
+      ]);
       if ($date_object !== null) {
         // Adjust the time back to the user's timezone
-        $controlCode = '<time>' . $date_object->i18nFormat($dateFormat) . '</time>';
+        $element = '<time>' . $date_object->i18nFormat($dateFormat) . '</time>';
       }
 
       // Return this to the generic control() function
-      return ['controlCode' => $controlCode,
-              'coptions' => [],
-              'cssClass' => '',
-              'labelIsTextOnly' => true];
-      return $this->control($fieldName, $coptions, ctrlCode: $controlCode, labelIsTextOnly: true);
+      return $element;
     }
 
     // Special-case the very common "valid_from" and "valid_through" fields, so we won't need
@@ -289,604 +268,195 @@ public function dateField(string $fieldName, string $dateType=DateTypeEnum::Stan
     ];
 
     // Create a text field to hold our value and call the datePicker
-    $controlCode = $this->Form->text($fieldName, $coptions) . $this->getView()->element('datePicker', $date_picker_args);
-
-    // Specify a class on the <li> form control wrapper
-    $liClass = 'fields-datepicker';
-    // Pass everything to the generic control() function
-    return ['controlCode' => $controlCode,
-            'coptions' => $coptions,
-            'labelIsTextOnly' => false,
-            'cssClass' => $liClass];
-  }
-  
-  /**
-   * End a set of form controls.
-   *
-   * @since  COmanage Registry v5.0.0
-   * @return string Control Set end HTML
-   */
-  
-  public function endControlSet(): string {
-    $this->modelName = null;
-    
-    return "</ul>\n";
-  }
-  
-  /**
-   * End a form line.
-   *
-   * @since  COmanage Registry v5.0.0
-   * @return string Line end HTML
-   */
-  
-  protected function endLine(): string {
-    return "</div></li>\n";
+    return $this->Form->text($fieldName, $coptions) . $this->getView()->element('datePicker', $date_picker_args);
   }
 
   /**
    * Create the actual Form element
    *
-   * @param   string       $fieldName  Form field
-   * @param   array        $options    FormHelper control options
-   *                                   By setting the options you are requesting a select field
-   * @param   string|null  $labelText  Label text (fieldName language key used by default)
-   * @param   string|null  $ctrlCode   Control code passed in from wrapper functions
-   * @param   string       $prefix     Field prefix - used for API Usernames
-   * @param   string|null  $controlType
+   * @param   string       $fieldName     Form field
+   * @param   array|null   $fieldOptions  The second parameter of the Form->control helper. List of element options
+   * @param   string|null  $fieldLabel    Custom label thext
+   * @param   string       $fieldPrefix   If the field has a specil prefix provide the value
+   * @param   string|null  $fieldType     Field type to override the one calculated from the schema
    *
-   * @return string  HTML for control
+   * @return string  HTML element
    * @since  COmanage Registry v5.0.0
    */
-  protected function formControl(string $fieldName,
-                                 array  $options = [],
-                                 string $labelText = null,
-                                 string $ctrlCode = null,
-                                 string $prefix = '',
-                                 string $controlType = null): string {
-    $coptions = $options;
-    $coptions['label'] = $options['label'] ?? false;
-    $coptions['readonly'] =
-      !$this->editable
-      || (isset($options['readonly']) && $options['readonly'])
-      // Plugins can't be changed after the parent object is instantiated
-      || ($fieldName == 'plugin' && $this->action == 'edit');
-    // Selects, Checkboxes, and Radio Buttons use "disabled"
-    $coptions['disabled'] = $coptions['readonly'];
-
-    // Get the field type from the map of fields (e.g. 'boolean', 'string', 'timestamp')
-    $fieldMap = $this->getView()->get('vv_field_types');
-    $fieldType = $controlType ?: $fieldMap[$fieldName];
+  public function formField(string $fieldName,
+                            array  $fieldOptions = null,
+                            string $fieldLabel = null,
+                            string $fieldPrefix = '',
+                            string $fieldType = null): string
+  {
+    $fieldArgs = $fieldOptions ?? [];
+    $fieldArgs['label'] = $fieldOptions['label'] ?? false;
+    $fieldArgs['readonly'] = !$this->editable
+                             || (isset($fieldOptions['readonly']) && $fieldOptions['readonly'])
+                             || ($fieldName == 'plugin' && $this->action == 'edit');
 
-    // Remove prefix from field value
-    if(!empty($prefix) && !empty($this->getView()->get('vv_obj')->$fieldName)) {
-      $vv_obj = $this->getView()->get('vv_obj');
-      $fieldValue = $vv_obj->$fieldName;
-      $fieldValueTemp = str_replace($prefix, '', $fieldValue);
-      $vv_obj->$fieldName = $fieldValueTemp;
-      $this->getView()->set('vv_obj', $vv_obj);
-    }
+    // Selects, Checkboxes, and Radio Buttons use "disabled"
+    $fieldArgs['disabled'] = $fieldArgs['readonly'];
+    $fieldArgs['required'] = $this->isReqField($fieldName)
+                             || (isset($fieldOptions['required']) && $fieldOptions['required']);
 
-    if($fieldName != 'status'
-      && !isset($options['empty'])
-      && (!isset($options['suppressBlank']) || !$options['suppressBlank'])) {
-      // Cause any select (except status) to render with a blank option, even
-      // if the field is required. This makes it clear when a value need to be set.
-      // Note this will be ignored for non-select controls.
-      $coptions['empty'] = true;
-    }
+    // Cause any select (except status) to render with a blank option, even
+    // if the field is required. This makes it clear when a value needs to be set.
+    // Note this will be ignored for non-select controls.
+    $fieldArgs['empty'] = !\in_array($fieldName, ['status', 'sync_status_on_delete'], true)
+                          || (isset($fieldOptions['empty']) && $fieldOptions['empty']);
 
-    // A boolean field is a checkbox. Set the label and class to improve rendering
-    // and accessibility.
-    if($fieldType == 'boolean') {
-      $coptions['label'] = $labelText;
-      $coptions['class'] = 'form-check-input';
-    }
+    // Manipulate the vv_object for the hasPrefix use case
+    $this->handlePrefix($fieldPrefix, $fieldName);
 
+    // Get the field type from the map of fields (e.g. 'boolean', 'string', 'timestamp')
+    $fieldType = $fieldType ?? $this->getFieldType($fieldName);
     // Generate the form control or pass along the markup generated in a wrapper function
-    return empty($ctrlCode) ? $this->Form->control($fieldName, $coptions) : $ctrlCode;
-
+    return match($fieldType) {
+      // A boolean field is a checkbox. Set the label and class to improve rendering
+      // and accessibility.
+      'boolean'   => $this->Form->control($fieldName, [
+                                            // First import and then overwrite
+                                            ...$fieldArgs,
+                                            'label' => $fieldLabel,
+                                            'class' => 'form-check-input',
+                                          ]),
+      'date'      => $this->dateField($fieldName, DateTypeEnum::DateOnly),
+      'datetime',
+      'timestamp' => $this->dateField($fieldName),
+      default     => $this->Form->control($fieldName, $fieldArgs)
+    };
   }
 
   /**
-   * Generate a form info (control, value) box.
-   *
-   * @since  COmanage Registry v5.0.0
-   * @param  string  $content    Content HTML
-   * @param  string  $beforeField Markup to be placed before/above the field
-   * @param  string  $afterField  Markup to be placed after/below the field
-   * @return string              Form Info HTML
+   * @return object|null
    */
-  
-  protected function formInfoDiv(string $content, 
-                                 string $beforeField = '', 
-                                 string $afterField = ''): string {
-    $div  = '<div class="field-info">' . PHP_EOL;
-    if(!empty($beforeField)) {
-      $div .= $beforeField . PHP_EOL;
-    }
-    $div .= $content . PHP_EOL;
-    if(!empty($afterField)) {
-      $div .= $afterField . PHP_EOL;  
-    }
-    $div .= '</div>' . PHP_EOL;
-    
-    return $div;
+  public function getEntity(): ?object
+  {
+    return $this->entity;
   }
 
   /**
-   * Create grouped control elements. By default, the elements will be placed one after the other, inline,
-   * with a direction left to right. For that need to occupy the whole row we defined the 'singleRowItem'
-   * configuration property that will add an inline Bootstrap css rule. The rule will override the default
-   * behavior
+   * @param   string  $field
    *
-   * @param   array   $fields
-   * @param   string  $pseudoFieldName
-   * @param   string  $beforeField  Markup to be placed before/above the field
-   * @param   string  $afterField   Markup to be placed after/below the field
-   *
-   * @return string              Form Info HTML
-   * @since  COmanage Registry v5.0.0
+   * @return string|null
    */
-
-  public function groupedControls(array $fields,
-                                  string $pseudoFieldName,
-                                  string $beforeField = '',
-                                  string $afterField = ''): string {
-    $content = '';
-    foreach ($fields as $fieldName => $fieldOptions) {
-      $dblock = isset($fieldOptions['singleRowItem']) && $fieldOptions['singleRowItem'] ? 'd-block' : '';
-      $content .= "<div class='subfield subfield-cols {$dblock}'>" . PHP_EOL;
-      $content .= '<div class="field-col">' . PHP_EOL;
-      $content .= $this->formControl($fieldName, $fieldOptions['options'] ?? []) . PHP_EOL;
-      $content .= '</div>' . PHP_EOL;
-      $content .= '</div>' . PHP_EOL;
-    }
-    $mn = $this->modelName;
-
-    return $this->startLine()
-      . $this->formNameDiv(
-        fieldName: $pseudoFieldName,
-        labelText: __d('field', $mn . '.' . $pseudoFieldName),
-        fieldType: 'string',
-        fieldNameClasses: 'field-name align-top'
-      )
-      . $this->formInfoDiv($content, $beforeField, $afterField)
-      . $this->endLine();
+  public function getFieldType(string $field): ?string
+  {
+    return $this->fieldTypes[$field] ?? null;
   }
 
   /**
-   * Generate a form info (control, value) box with a non editable prefix.
-   *
-   * @since  COmanage Registry v5.0.0
-   * @param  string  $content     Content HTML
-   * @param  string  $prefix      Prefix value
-   * @param  string  $beforeField Markup to be placed before/above the field
-   * @param  string  $afterField  Markup to be placed after/below the field
-   * @return string               Form Info HTML
+   * @return array
    */
-
-  protected function formInfoWithPrefixDiv(string $context, 
-                                           string $prefix, 
-                                           string $beforeField = '', 
-                                           string $afterField = ''): string {
-    $div  = '<div class="field-info">' . PHP_EOL;
-    if(!empty($beforeField)) {
-      $div .= $beforeField . PHP_EOL;
-    }
-    $div .= '<div class="input-group mb-3">' . PHP_EOL;
-    $div .= '<div class="input-group-prepend">' . PHP_EOL;
-    $div .= '<span class="input-group-text" id="basic-addon3">' . $prefix . '</span>';
-    $div .= '</div>' . PHP_EOL;
-    $div .= $context;
-    $div .= '</div>';
-    if(!empty($afterField)) {
-      $div .= $afterField . PHP_EOL;
-    }
-    $div .= '</div>';
-
-    return $div;
+  public function getFieldTypes(): array
+  {
+    return $this->fieldTypes;
   }
 
   /**
-   * Generate a form name (label, description) box.
-   *
-   * @param   string       $fieldName         Form field
-   * @param   string|null  $labelText         Label text (fieldName language key used by default)
-   * @param   string       $fieldType         Type of field (string, boolean, timestamp, etc.)
-   * @param   boolean      $labelIsTextOnly   True if label should be text only. Otherwise, false.
-   * @param   string|null  $fieldNameClasses  Override the field-name classes
-   * @param   string|null  $fieldTitleClasses Override the field-title classes
-   * @param   string|null  $fieldDescClasses  Override the field-description classes
-   *
-   * @return string             Form Name HTML
-   * @since  COmanage Registry v5.0.0
+   * @return string|null
    */
-  
-  protected function formNameDiv(string $fieldName,
-                                 ?string $labelText,
-                                 string $fieldType,
-                                 bool $labelIsTextOnly = false,
-                                 ?string $fieldNameClasses = null,
-                                 ?string $fieldTitleClasses = null,
-                                 ?string $fieldDescClasses = null
-  ): string {
-    $label = $labelText;
-    $desc = null;
-    
-    // We'll accept a fieldName of the form other_models.0.foo for forms that
-    // request associated data. Note, however, that model names for language
-    // keys are OtherModel, so we'll need to inflect. 
-    
-    $mn = $this->modelName;
-    $fn = $fieldName;
-    
-    if(str_contains($fieldName, '.')) {
-      // othermodels.0.field
-      
-      $bits = explode('.', $fieldName, 3);
-      $mn = Inflector::classify($bits[0]);
-      $fn = $bits[2];
-    }
-    
-    // First try to autogenerate the field label (if we weren't given one).
-    
-    $pluginDomain = (!empty($this->pluginName)
-                      ? Inflector::underscore($this->pluginName)
-                      : null);
-    
-    if(!$label) {
-      // We autogenerate field labels and descriptions from the field name.
-      
-      // We loop over the field generation logic twice, first for a plugin
-      // context (if set) and then generally (if no plugin localization was found).
-
-      // We use $core as the variable for this loop, so the rest of the code
-      // is easier to read (!$core = plugin)
-      for($core = 0;$core < 2;$core++) {
-        if(!$core && empty($this->pluginName)) {
-          // No plugin set, just go to the core field checks
-          continue;
-        }
-
-        // Is there a model specific key? For plugins, this will be in field.Model.Field
-
-        $key = (!$core ? 'field.' : '') . "$mn.$fn";
-        $label = __d(($core ? 'field' : $pluginDomain), $key);
-
-        if($label == $key) {
-          // Model specific label not found, try again for a general label
-
-          $f = null;
-
-          if(preg_match('/^(.*?)_id$/', $fn, $f)) {
-            // Map foreign keys (foo_id) to the controller label
-            $key = (!$core ? 'controller.' : '') . Inflector::camelize(Inflector::pluralize($f[1]));
-            $label = __d(($core ? 'controller' : $pluginDomain), $key, [1]);
-
-            if($key != $label) {
-              break;
-            }
-          }
-          
-          // Just look up the key
-          $key = (!$core ? 'field.' : '') . $fn;
-          $label = __d(($core ? 'field' : $pluginDomain), $key);
-
-          if($key != $label) {
-            break;
-          }
-        } else {
-          // If we found a key, break the loop
-          break;
-        }
-      }
-    }
-    
-    // We try to automagically determine if a description for the field exists by
-    // looking for the corresponding .desc language translation.
-    
-    for($core = 0;$core < 2;$core++) {
-      if(!$core && empty($this->pluginName)) {
-        // No plugin set, just go to the core field checks
-        continue;
-      }
-
-      $key = (!$core ? "field." : "") . "$mn.$fn.desc";
-      $desc = __d(($core ? 'field' : $pluginDomain), $key);
+  public function getModelName(): ?string
+  {
+    return $this->modelName;
+  }
 
-      // If the description is the literal key we just generated, there is no description
-      if($desc == $key) {
-        $desc = null;
-      } else {
-        break;
-      }
-    }
+  /**
+   * @return string|null
+   */
+  public function getPluginName(): ?string
+  {
+    return $this->pluginName;
+  }
 
-    return '<div class="'. ($fieldNameClasses  ?? 'field-name') . '">'
-             . '<div class="'. ($fieldTitleClasses  ?? 'field-title') . '">'
-             // Form Label
-             . (!($labelIsTextOnly) && ($fieldType != 'boolean') ? $this->Form->label($fn, $label) : $label)
-             . ($this->editable && in_array($fn, $this->reqFields) ? $this->requiredSpanElement() : '')
-             . '</div>' // field-title div
-             // Description element
-             . ($desc ? '<div class="'. ($fieldDescClasses  ?? 'field-desc') . '">' . $desc . '</div>' : '') .'
-           </div>';
+  /**
+   * @return array
+   */
+  public function getReqFields(): array
+  {
+    return $this->reqFields;
   }
-  
+
   /**
-   * Emit a People Autocomplete (PrimeVue) control for selecting a person
-   *
-   * @param  string $fieldName            Field name of input field
-   * @param  array  $viewConfigParameters
-   * @param  string $personType           Type of person autocomplete to use (XXX should be an enum, and a default should be set)
+   * For the records that have a value like co_x.value, and we want to handle
+   * the value separate from the field
    *
-   * @return string            Source HTML
-   * @since  COmanage Registry v5.0.0
+   * @param   string  $fieldPrefix   e.g. co_2.
+   * @param   string  $fieldName     e.g. username
    *
+   * @return void
    */
-  
-  public function peopleAutocompleteControl(string $fieldName, array $viewConfigParameters = [], string $personType = 'coperson'): string {
-    if($this->action == 'view') {
-      // return the member name value as plaintext
-      $coptions = ['type' => 'text'];
-      $entity = $this->getView()->get('vv_obj');
-      $controlCode = $entity->$fieldName;
-      
-      // Return this to the generic control() function
-      return $this->control($fieldName, $coptions, ctrlCode: $controlCode, labelIsTextOnly: true);
-      
-    } else {
-      // Create the options array for the (text input) form control
-      $coptions = [];
-      $coptions['class'] = 'form-control people-autocomplete';
-      $coptions['placeholder'] = __d('operation','autocomplete.people.placeholder');
-      $coptions['id'] = $fieldName;
-      $coptions['value'] =  '';
-      
-      $entity = $this->getView()->get('vv_obj');
-      
-      // Get the existing values, if present
-      if(!empty($entity->$fieldName)) {
-        $coptions['value'] =  ''; // XXX put the ID here.
-      }
-            
-      // Create a field name for the autocomplete input
-      $autoCompleteFieldName = 'cm_autocomplete_' . $fieldName;
-      
-      // Because we use JavaScript to set the value of the hidden field,
-      // disable form-tamper checking for the autocomplete fields.
-      // XXX We ought not have to do this for the hidden field ($fieldName) at least
-      $this->Form->unlockField($fieldName);
-      $this->Form->unlockField($autoCompleteFieldName);
-      
-      $autocompleteArgs = [
-        'type' => 'field',
-        'fieldName' => $fieldName,
-        'personType' => $personType,
-        'htmlId' => $autoCompleteFieldName,
-        'viewConfigParameters' => $viewConfigParameters
-      ];
-      
-      // Create a hidden field to hold our value and emit the autocomplete widget
-      $controlCode = $this->Form->hidden($fieldName, $coptions)
-        . $this->getView()->element('peopleAutocomplete', $autocompleteArgs);
-      
-      // XXX the numeric value passed to 'autocomplete.people.desc' should be derived from config; it is the minLength value for starting autocomplete.
-      $autoCompleteDesc = '<div class="field-desc"><span class="material-icons">info</span> ' . __d('operation','autocomplete.people.desc',['2']) . '</div>';
-      
-      // Specify a class on the <li> form control wrapper
-      $liClass = 'fields-people-autocomplete';
-      
-      // Pass everything to the generic control() function
-      return $this->control(
-                         $fieldName,
-                         $coptions,
-        ctrlCode:        $controlCode,
-        cssClass:        $liClass,
-        afterField:      $autoCompleteDesc,
-        labelIsTextOnly: true
-      );
+  protected function handlePrefix(string $fieldPrefix, string $fieldName): void
+  {
+    // Remove prefix from field value
+    if(!empty($fieldPrefix) && !empty($this->getEntity()->$fieldName)) {
+      $fieldValue = $this->getEntity()->$fieldName;
+      $this->getEntity()->$fieldName = str_replace($fieldPrefix, '', $fieldValue);
+      $this->getView()->set('vv_obj', $this->getEntity());
     }
   }
 
   /**
-   * Static required Span Element
-   *
-   * @return string
-   * @since  COmanage Registry v5.0.0
+   * @return bool
    */
-  protected function requiredSpanElement(): string
+  public function isEditable(): bool
   {
-    return "<span class='required' aria-hidden='true'>*</span>"
-           . "<span class='visually-hidden'>{__d('field', 'required')}</span>";
+    return $this->editable;
   }
 
   /**
-   * Static Not Set Div Element
+   * @param   string  $field
    *
-   * @return string
-   * @since  COmanage Registry v5.0.0
+   * @return bool
    */
-
-  protected function notSetElement(): string
+  public function isReqField(string $field): bool
   {
-    return '<div class="not-set">' . __d('information', 'notset') . '</div>';
+    return \in_array($field, $this->reqFields, true);
   }
 
   /**
    * Emit a source control for an MVEA that has a source_foo_id field pointing
    * to an External Identity attribute.
-   * 
+   *
+   * @param   Entity  $entity  Entity to emit control for
+   *
+   * @return string             Source Link
    * @since  COmanage Registry v5.0.0
-   * @param  Entity   $entity   Entity to emit control for
-   * @return string             Source HTML
    */
-  
-  public function sourceControl($entity): string {
+  public function sourceLink($entity): string
+  {
     // eg: Identifiers
-    $modelName = StringUtilities::entityToClassName($entity);
     // eg: source_identifier_id, or source_external_identity_role_id
     $sourceFK = $this->getView()->get('vv_source_fk');
-    // eg: source_identifier - we need to construct this from the $sourceFK
-    $sourceEntityName = substr($sourceFK, 0, strlen($sourceFK)-3);
-    // In most cases $sourceModelName = $modelName, but not for PersonRoles
+    // e.g.: source_identifier - we need to construct this from the $sourceFK
+    $sourceEntityName = substr($sourceFK, 0, strlen($sourceFK) - 3);
+    // In most cases, $sourceModelName = $modelName, but not for PersonRoles
     $sourceModelName = substr(StringUtilities::foreignKeyToClassName($sourceFK), 6);
 
-    $linkHtml = '<div>';
-
-    if(!empty($entity->$sourceFK)) {
-      $linkHtml .= $this->Html->Link(
+    $link = '';
+    if (!empty($entity->$sourceFK)) {
+      $link .= $this->Html->Link(
         title: __d('controller', $sourceModelName, [1]),
-        url: [
-          'controller'  => $sourceModelName,
-          'action'      => 'view',
-          $entity->$sourceFK
-        ]
-      );
-    }
-
-    if(!empty($entity->$sourceEntityName)) {
-      $linkHtml .= ', ' . $this->Html->Link(
-        title: __d('controller', 'ExternalIdentities', [1]),
-        url: [
-                 'controller'  => 'external_identities',
-                 'action'      => 'view',
-                 $entity->$sourceEntityName->external_identity_id
+        url:   [
+                 'controller' => $sourceModelName,
+                 'action'     => 'view',
+                 $entity->$sourceFK
                ]
       );
     }
 
-    $linkHtml .= '</div>';
-
-    return $this->startLine()
-           . $this->formNameDiv(
-                fieldName: $sourceFK,
-                labelText: __d('field', 'source'),
-                fieldType: 'string'
-             )
-           . $linkHtml
-           . $this->endLine();
-  }
-
-  /**
-   * Generate a status control (a read only status with an optional link button).
-   *
-   * @param   string       $fieldName        Form field
-   * @param   string       $status           Status text
-   * @param   array        $link             Link information, including 'url', 'label', 'class', 'confirm'
-   * @param   string|null  $labelText        Label text (fieldName language key used by default)
-   * @param   boolean      $labelIsTextOnly  true if <label> wrapper should not be included in the markup
-   *
-   * @return string
-   * @since  COmanage Registry v5.0.0
-   */
-  
-  public function statusControl(string $fieldName, 
-                                string $status, 
-                                array  $link=[], 
-                                string $labelText = null,
-                                bool   $labelIsTextOnly = false): string {
-    $linkHtml = $status;
-    
-    if($link) {
-      // Construct HTML for the requested link
-      
-      if(!empty($link['label'])) {
-        // Create a separate link after $status
-        
-        $linkHtml .= ' ' . $this->Html->link(
-          $link['label'],
-          $link['url'],
-          $link
-        );
-      } else {
-        // Make $status the link
-        
-        $linkHtml = $this->Html->link(
-          $status,
-          $link['url'],
-          // Just pass whatever other args are specified
-          $link
+    if (!empty($entity->$sourceEntityName)) {
+      $link .= ', ' . $this->Html->Link(
+          title: __d('controller', 'ExternalIdentities', [1]),
+          url:   [
+                   'controller' => 'external_identities',
+                   'action'     => 'view',
+                   $entity->$sourceEntityName->external_identity_id
+                 ]
         );
-      }
     }
-     
-    return $this->startLine()
-           . $this->formNameDiv($fieldName, $labelText, 'string', $labelIsTextOnly)
-           . $this->formInfoDiv($linkHtml)
-           . $this->endLine();
-  }
-
-  /**
-   * Start a set of form controls.
-   *
-   * @param   string       $modelName  Model name for form
-   * @param   string       $action     Current action
-   * @param   boolean      $editable   True if controls are read/write, false for read only
-   * @param   array        $reqFields  Array of required fields
-   * @param   null         $entity     Entity object (if set, null on add)
-   * @param   string|null  $pluginName
-   *
-   * @return string
-   * @since  COmanage Registry v5.0.0
-   */
-  
-  public function startControlSet(string $modelName, 
-                                  string $action, 
-                                  bool $editable, 
-                                  array $reqFields,
-                                  $entity=null,
-                                  ?string $pluginName=null): string {
-    $this->editable = $editable;
-    $this->modelName = $modelName;
-    $this->pluginName = $pluginName;
-    $this->reqFields = $reqFields;
-    $this->entity = $entity;
-    $this->action = $action;
-
-    return '<ul id="' . $action . '_' . $modelName . '" class="fields form-list">' . "\n";
+    return $link;
   }
 
-  /**
-   * Start a form line.
-   *
-   * @param   string|null  $class  Optional class to apply to the line
-   *
-   * @return string
-   * @since  COmanage Registry v5.0.0
-   */
-  
-  protected function startLine(string $class=null): string {
-    $ret = '<li';
-    
-    if($class) {
-      $ret .= ' class="' . $class . '"';
-    }
-    
-    $ret .= '><div class="field">';
-    
-    return $ret;
-  }
-  
-  /**
-   * Emit a submit control.
-   *
-   * @since  COmanage Registry v5.0.0
-   * @param  string  $label Text for submit button
-   * @return string
-   */
-  
-  public function submit(string $label): string {
-    return '<li class="fields-submit">
-      <div class="field">
-        <div class="field-name">
-          <span class="required">* ' . __d('field', 'required') . '</span>
-        </div>
-        <div class="field-info">
-          ' . $this->Form->submit($label) . '
-        </div>
-      </div>  
-    </li>';
-  }
 }
\ No newline at end of file
diff --git a/app/templates/AdHocAttributes/fields.inc b/app/templates/AdHocAttributes/fields.inc
index b1f57e918..377b9b0e0 100644
--- a/app/templates/AdHocAttributes/fields.inc
+++ b/app/templates/AdHocAttributes/fields.inc
@@ -26,11 +26,26 @@
  */
 
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
-  print $this->Field->control('tag');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'tag'
+    ]]);
 
-  print $this->Field->control('value');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'value'
+    ]]);
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
+}
 
-  print $this->Field->sourceControl($vv_obj);
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
 }
diff --git a/app/templates/Addresses/fields.inc b/app/templates/Addresses/fields.inc
index 757f13db9..4c23a1b46 100644
--- a/app/templates/Addresses/fields.inc
+++ b/app/templates/Addresses/fields.inc
@@ -28,26 +28,42 @@
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
   // Dynamic required fields is automatically handled by FormHelper via the
   // validation rules
-  
-  print $this->Field->control('street');
+  foreach (['street',
+             'room',
+             'locality',
+             'state',
+             'postal_code',
+             'country',
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
 
-  print $this->Field->control('room');
-  
-  print $this->Field->control('locality');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_type
+      ]
+    ]]);
 
-  print $this->Field->control('state');
-  
-  print $this->Field->control('postal_code');
-  
-  print $this->Field->control('country');
-
-  print $this->Field->control('type_id', ['default' => $vv_default_type]);
-
-  print $this->Field->control('language');
-
-  print $this->Field->control('description');
-
-  print $this->Field->control('frozen');
+  foreach (['language',
+             'description',
+             'frozen',
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
+}
 
-  print $this->Field->sourceControl($vv_obj);
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
 }
diff --git a/app/templates/ApiUsers/fields-generate.inc b/app/templates/ApiUsers/fields-generate.inc
index 293f2a1c1..1656cc4d7 100644
--- a/app/templates/ApiUsers/fields-generate.inc
+++ b/app/templates/ApiUsers/fields-generate.inc
@@ -25,8 +25,18 @@
  * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
  */
 
-print $this->Field->banner(__d('information', 'api.key'));
+print $this->element('notify/banner', [ 'info' => __d('information', 'api.key')]);
 
-print $this->Field->statusControl('username', $vv_obj->username);
+print $this->element('form/listItem', [
+  'arguments' => [
+    'fieldName' => 'username',
+    'status' => $vv_obj->username,
+  ]
+]);
 
-print $this->Field->statusControl('api_key', $vv_api_key);
+print $this->element('form/listItem', [
+  'arguments' => [
+    'fieldName' => 'api_key',
+    'status' => $vv_api_key,
+  ]
+]);
diff --git a/app/templates/ApiUsers/fields.inc b/app/templates/ApiUsers/fields.inc
index 2c3887e6e..e8cba5cac 100644
--- a/app/templates/ApiUsers/fields.inc
+++ b/app/templates/ApiUsers/fields.inc
@@ -26,18 +26,23 @@
  */
 
 // This view does not support read-only
-if($vv_action == 'add' || $vv_action == 'edit') {  
+if($vv_action == 'add' || $vv_action == 'edit') {
   if($vv_cur_co->id == 1) {
-    print $this->Field->banner(__d('information', 'api.cmp'));
+    print $this->element('banner', ['info' => __d('information', 'api.cmp')]);
   }
-  
+
   // AR-ApiUser-3 For namespacing purposes, API Users are named with a prefix consisting of the string "co_#.".
-  print $this->Field->control('username', prefix: 'co_' . $vv_cur_co->id . '.');
-  
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'username',  // string
+      'fieldPrefix' => 'co_' . $vv_cur_co->id . '.'
+    ]
+  ]);
+
   // We link to the "Generate" button on edit only
   $generateLink = [];
   $labelIsTextOnly = false;
-  
+
   if(!empty($vv_obj->id)) {
     $generateLink = [
       'url' => [
@@ -49,22 +54,46 @@ if($vv_action == 'add' || $vv_action == 'edit') {
      'class' => 'provisionbutton nospin btn btn-primary btn-sm',
      'confirm' => __d('operation', 'api.key.generate.confirm')
     ];
-    
+
     $labelIsTextOnly = true;
   }
-  
-  print $this->Field->statusControl('api_key',
-                                    !empty($vv_obj->api_key) ? __d('enumeration', 'SetBooleanEnum.1') : __d('enumeration', 'SetBooleanEnum.0'),
-                                    $generateLink,
-                                    labelIsTextOnly: $labelIsTextOnly);
-  
-  print $this->Field->control('status', ['empty' => false]);
-  
-  print $this->Field->dateControl('valid_from');
-  
-  print $this->Field->dateControl('valid_through');
-  
-  print $this->Field->control('remote_ip');
-  
-  print $this->Field->control('privileged');
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'api_key',
+      'status' => !empty($vv_obj->api_key) ? __d('enumeration', 'SetBooleanEnum.1') : __d('enumeration', 'SetBooleanEnum.0'),
+      'link' => $generateLink,
+      'labelIsTextOnly' => $labelIsTextOnly
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status', // select
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'valid_from', // timestamp
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'valid_through', // timestamp
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'remote_ip', // string
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'privileged', // boolean
+    ]
+  ]);
 }
diff --git a/app/templates/CoSettings/fields.inc b/app/templates/CoSettings/fields.inc
index 5db14134a..b7ff8281e 100644
--- a/app/templates/CoSettings/fields.inc
+++ b/app/templates/CoSettings/fields.inc
@@ -28,54 +28,103 @@
 <?php
 // This view does not support add or read-only
 if($vv_action == 'edit') {
-  print $this->Field->control('required_fields_address', ['suppressBlank' => true]);
-  
-  print $this->Field->control('default_address_type_id');
-  
-  print $this->Field->control('default_email_address_type_id');
-  
-  print $this->Field->control('default_identifier_type_id');
-  
-  print $this->Field->control('default_name_type_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'required_fields_address',
+      'fieldOptions' => ['empty' => false]
+    ]]);
 
-  print $this->Field->control('permitted_fields_name', ['suppressBlank' => true]);
-  
-  print $this->Field->control('required_fields_name', ['suppressBlank' => true]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'default_address_type_id'
+    ]]);
 
-  print $this->Field->control('default_pronoun_type_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'default_email_address_type_id'
+    ]]);
 
-  print $this->Field->control('default_telephone_number_type_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'default_identifier_type_id'
+    ]]);
 
-  print $this->Field->control('permitted_fields_telephone_number', ['suppressBlank' => true]);
-  
-  print $this->Field->control('default_url_type_id');
-  
-  print $this->Field->control('search_global_limit');
-  
-  print $this->Field->control('search_global_limited_models');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'default_name_type_id'
+    ]]);
 
-  print $this->Field->groupedControls(
-    [
-      'person_picker_email_address_type_id' => [
-        'options' => [
-          'suppressBlank' => true,
-          'label' => __d('field', 'mail'),
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'permitted_fields_name',
+      'fieldOptions' => ['empty' => false]
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'required_fields_name',
+      'fieldOptions' => ['empty' => false]
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'default_pronoun_type_id'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'default_telephone_number_type_id'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'permitted_fields_telephone_number',
+      'fieldOptions' => ['empty' => false]
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'default_url_type_id'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'search_global_limit'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'search_global_limited_models'
+    ]]);
+
+    print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'person_picker_display_fields',
+      'groupedControls' =>  [
+        // each key is the fieldName of the control we are going to create
+        'person_picker_email_address_type_id' => [
+          'fieldOptions' => [
+            'label' => __d('field', 'mail'),
+          ],
         ],
-      ],
-      'person_picker_identifier_type_id' => [
-        'options' => [
-          'suppressBlank' => true,
-          'label' => __d('field', 'identifier'),
+        'person_picker_identifier_type_id' => [
+          'fieldOptions' => [
+            'label' => __d('field', 'identifier'),
+          ],
         ],
+        'person_picker_display_types' => [
+          'singleRowItem' => true
+        ]
       ],
-      'person_picker_display_types' => [
-        'singleRowItem' => true
-      ]
-    ],
-    'person_picker_display_fields'
-  );
+    ]]);
 
-  print $this->Field->control('email_smtp_server_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'email_smtp_server_id'
+    ]]);
 
-  print $this->Field->control('email_delivery_address_type_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'email_delivery_address_type_id'
+    ]]);
 }
diff --git a/app/templates/Cos/fields.inc b/app/templates/Cos/fields.inc
index 258f85d7d..fd9658a47 100644
--- a/app/templates/Cos/fields.inc
+++ b/app/templates/Cos/fields.inc
@@ -27,9 +27,18 @@
 
 // This view supports read-only only for the COmanage CO
 if($vv_action == 'add' || $vv_action == 'edit' || ($vv_action == 'view' && $vv_obj->name == 'COmanage')) {
-  print $this->Field->control('name');
-  
-  print $this->Field->control('description');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'name'
+    ]]);
 
-  print $this->Field->control('status', ['empty' => false]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'description'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status'
+    ]]);
 }
diff --git a/app/templates/Cos/select.php b/app/templates/Cos/select.php
index b62bb20a5..b18e1833b 100644
--- a/app/templates/Cos/select.php
+++ b/app/templates/Cos/select.php
@@ -35,7 +35,7 @@
 </div>
 
 <?php if(count($vv_available_cos) == 0): ?>
-  <?= $this->Alert->alert(__d('information','cos.none'), 'warning') ?>
+  <?= $this->element('notify/alert', ['message' => __d('information','cos.none')]) ?>
 <?php else: // vv_available_cos ?>
   <p><?= __d('information', 'cos.select'); ?></p>
   <div id="fpList" class="co-grid co-grid-with-header container">
diff --git a/app/templates/Cous/fields.inc b/app/templates/Cous/fields.inc
index 89aa3fd11..60089c412 100644
--- a/app/templates/Cous/fields.inc
+++ b/app/templates/Cous/fields.inc
@@ -27,11 +27,19 @@
 
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('name');
-  
-  print $this->Field->control('description');
+  print $this->element('form/listItem', [
+    'arguments' => ['fieldName' => 'name']
+  ]);
+  print $this->element('form/listItem', [
+    'arguments' => ['fieldName' => 'description']
+  ]);
 
   if(!empty($parents)) {
-    print $this->Field->control('parent_id', ['empty' => true], __d('field', 'parent_id'));
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'parent_id',
+        'fieldLabel' => __d('field', 'parent_id')
+      ]
+    ]);
   }
 }
diff --git a/app/templates/Dashboards/configuration.php b/app/templates/Dashboards/configuration.php
index 10c307cb7..1ecc290c9 100644
--- a/app/templates/Dashboards/configuration.php
+++ b/app/templates/Dashboards/configuration.php
@@ -145,6 +145,10 @@
     ];
   ?>
   <div class="config-platform-notice">
-    <?= $this->Alert->alert(__d('information','cmp.config.notice', $noticeUrls), 'information', true) ?>
+    <?= $this->element('notify/alert', [
+      'message' => __d('information','cmp.config.notice', $noticeUrls),
+      'type'    => 'information',
+      'dismissible' => true
+    ]) ?>
   </div>
 <?php endif; ?>
\ No newline at end of file
diff --git a/app/templates/Dashboards/search.php b/app/templates/Dashboards/search.php
index 3481f9fd2..e39f29d6b 100644
--- a/app/templates/Dashboards/search.php
+++ b/app/templates/Dashboards/search.php
@@ -59,13 +59,13 @@
 
   <?php if(!empty($indexBanners)): ?>
     <?php foreach($indexBanners as $b): ?>
-      <?=  $this->Alert->alert($b, 'warning') ?>
+      <?= $this->element('notify/alert', ['message' => $b]) ?>
     <?php endforeach; // $indexBanners ?>
   <?php endif; // $indexBanners ?>
 
   <?php if(!empty($banners)): ?>
     <?php foreach($banners as $b): ?>
-      <?=  $this->Alert->alert($b, 'warning') ?>
+      <?= $this->element('notify/alert', ['message' => $b]) ?>
     <?php endforeach; // $banners ?>
   <?php endif; // $banners ?>
 </div>
diff --git a/app/templates/EmailAddresses/fields.inc b/app/templates/EmailAddresses/fields.inc
index 7676ffb3e..3c4d5065c 100644
--- a/app/templates/EmailAddresses/fields.inc
+++ b/app/templates/EmailAddresses/fields.inc
@@ -26,16 +26,44 @@
  */
 
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
-  print $this->Field->control('mail');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'mail'
+    ]]);
 
-  print $this->Field->control('type_id', ['default' => $vv_default_type]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_type
+      ]
+    ]]);
 
-  print $this->Field->control('description');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'description'
+    ]]);
 
 // XXX CFM-129 need to implement verification
-  print $this->Field->control('verified', ['readonly' => true]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'verified',
+      'fieldOptions' => [
+        'readonly' => true
+      ]
+    ]]);
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
 
-  print $this->Field->sourceControl($vv_obj);
 }
+
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
+}
\ No newline at end of file
diff --git a/app/templates/ExtIdentitySourceRecords/fields.inc b/app/templates/ExtIdentitySourceRecords/fields.inc
index 59d62580c..47df19b92 100644
--- a/app/templates/ExtIdentitySourceRecords/fields.inc
+++ b/app/templates/ExtIdentitySourceRecords/fields.inc
@@ -42,17 +42,23 @@ $noticeText = __d(
   ]
 );
 
-print $this->Alert->alert($noticeText, 'information', false);
+print $this->element('notify/alert', [
+  'message'     => $noticeText,
+  'type'        => 'information'
+]);
 
 // This view does not support add or edit
 if($vv_action == 'view') {
 // Link to External Identity, if known
-
-  print $this->Field->control('source_key');
-
-  print $this->Field->control('last_update');
-
-  print $this->Field->control('reference_identifier');
-
-  print $this->Field->control(fieldName: 'source_record', cssClass: 'source-record');
+  foreach([
+            'source_key',
+            'last_update',
+            'reference_identifier',
+            'source_record'
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]]);
+  }
 }
diff --git a/app/templates/ExternalIdentities/fields.inc b/app/templates/ExternalIdentities/fields.inc
index 65d4411d9..4f5eeaff2 100644
--- a/app/templates/ExternalIdentities/fields.inc
+++ b/app/templates/ExternalIdentities/fields.inc
@@ -43,11 +43,23 @@ if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
         )
       ]
     );
-    
-    print $this->Alert->alert($noticeText, 'information', false);
+
+    $this->element('notify/alert', [
+      'message'     => $noticeText,
+      'type'        => 'information'
+    ]);
+
   }
 
-  print $this->Field->control('status', ['empty' => false]);
-  
-  print $this->Field->dateControl('date_of_birth', \App\Lib\Enum\DateTypeEnum::DateOnly);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status'
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'date_of_birth', // date
+    ]
+  ]);
 }
diff --git a/app/templates/ExternalIdentityRoles/fields-nav.inc b/app/templates/ExternalIdentityRoles/fields-nav.inc
index 653919ff4..ca3a42217 100644
--- a/app/templates/ExternalIdentityRoles/fields-nav.inc
+++ b/app/templates/ExternalIdentityRoles/fields-nav.inc
@@ -34,7 +34,7 @@ $mveas = [
 ];
 
 // Name the MVEAs Entity Type
-$mveasEntityType = "external_identity_role";
+$mveasEntityType = 'external_identity_role';
 
 // $addMenuLinks is also given slightly different treatment from the typical $topLinks found in most views: 
 // it is a page-global menu used for adding MVEAs and is given special treatment in element/mveaCanvas.php.
diff --git a/app/templates/ExternalIdentityRoles/fields.inc b/app/templates/ExternalIdentityRoles/fields.inc
index abab0817b..33b5aef1a 100644
--- a/app/templates/ExternalIdentityRoles/fields.inc
+++ b/app/templates/ExternalIdentityRoles/fields.inc
@@ -26,24 +26,55 @@
  */
 
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
-  print $this->Field->control('affiliation_type_id', labelText: __d('field', 'affiliation'));
-  
-  print $this->Field->control('status', ['empty' => false]);
-  
-  print $this->Field->control('ordr');
-  
-  print $this->Field->control('title');
-  
-  print $this->Field->control('organization');
-  
-  print $this->Field->control('department');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'affiliation_type_id',
+      'fieldLabel' => __d('field', 'affiliation')
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status'
+    ]
+  ]);
+
+  foreach([
+            'ordr',
+            'title',
+            'organization'.
+            'department'
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
   
 // XXX need to clarify this is an _identifier_ not an actual Person FK
-  print $this->Field->control('sponsor_identifier', labelText: __d('field', 'sponsor'));
-  
-  print $this->Field->control('manager_identifier', labelText: __d('field', 'manager'));
-  
-  print $this->Field->dateControl('valid_from');
-  
-  print $this->Field->dateControl('valid_through');
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'sponsor_identifier',
+      'fieldLabel' => __d('field', 'sponsor')
+    ]
+  ]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'manager_identifier',
+      'fieldLabel' => __d('field', 'manager')
+    ]
+  ]);
+
+  foreach([
+            'valid_from',
+            'valid_through'
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 }
diff --git a/app/templates/ExternalIdentitySources/fields.inc b/app/templates/ExternalIdentitySources/fields.inc
index cd1ef8fc5..12d631fd0 100644
--- a/app/templates/ExternalIdentitySources/fields.inc
+++ b/app/templates/ExternalIdentitySources/fields.inc
@@ -28,14 +28,23 @@
 <?php
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('description');
-
-  print $this->Field->control('status', 
-                              ['default'  => \App\Lib\Enum\SyncModeEnum::Disabled]);
-  
-  print $this->Field->control('plugin');
-
-  print $this->Field->control('pipeline_id');
-  
-  print $this->Field->control('sor_label');
+  foreach([
+            'description',
+            'status',
+            'plugin',
+            'pipeline_id',
+            'sor_label',
+          ] as $field) {
+    $params =  [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ];
+    if($field == 'status') {
+      $params['arguments']['fieldOptions'] = [
+        'default'  => \App\Lib\Enum\SyncModeEnum::Disabled
+      ];
+    }
+    print $this->element('form/listItem', $params);
+  }
 }
diff --git a/app/templates/ExternalIdentitySources/retrieve.php b/app/templates/ExternalIdentitySources/retrieve.php
index b50364847..f0925635d 100644
--- a/app/templates/ExternalIdentitySources/retrieve.php
+++ b/app/templates/ExternalIdentitySources/retrieve.php
@@ -105,8 +105,7 @@
     );
   }
 ?>
-<?= $this->Alert->alert($noticeText, 'information', false) ?>
-
+<?= $this->element('notify/alert', ['message' => $noticeText,'type' => 'information']) ?>
 <div class="innerContent">
   <div class="table-container">
     <h3><?= __d('information','ExternalIdentitySourceRecords.metadata') ?></h3>
diff --git a/app/templates/ExternalIdentitySources/search.php b/app/templates/ExternalIdentitySources/search.php
index a7b841cec..65c166613 100644
--- a/app/templates/ExternalIdentitySources/search.php
+++ b/app/templates/ExternalIdentitySources/search.php
@@ -42,7 +42,10 @@
 </div>
 
 <?php if(empty($vv_search_attrs)): ?>
-  <?= $this->Alert->alert(__d('information', 'ExternalIdentitySources.search.attrs.none'), 'information', false)  ?>
+  <?= $this->element('notify/alert', [
+    'message' => __d('information', 'ExternalIdentitySources.search.attrs.none'),
+    'type' => 'information'
+  ]) ?>
 <?php else: // vv_search_attrs ?>
   <?php
     // Begin the form
diff --git a/app/templates/GroupMembers/fields.inc b/app/templates/GroupMembers/fields.inc
index 4775a33b5..f88c6b510 100644
--- a/app/templates/GroupMembers/fields.inc
+++ b/app/templates/GroupMembers/fields.inc
@@ -28,46 +28,54 @@
 if($vv_action == 'add') {
   if(!empty($vv_selected_person)) {
     // The person has been preselected. Created a hidden field, and present information about the person.
-    print $this->Form->hidden('person_id', ['value' => $vv_selected_person['id']]);
+    $hidden = [
+      'person_id' => $vv_selected_person['id']
+    ];
     
-    // Present the person information in the view:
-?>    
-    <li>
-      <div class="field">
-        <div class="field-name">
-          <div class="field-title">
-            <?= __d('field','name') ?>
-          </div>
-        </div>
-        <div class="field-info">
-          <span class="group-member-to-add-name">
-            <?= $vv_selected_person['name'] ?>
-          </span> 
-          <span class="group-member-to-add-id">
-            (<?= __d('information', 'entity.id', [$vv_selected_person['id']]) ?>)
-          </span>
-        </div>
-      </div>
-    </li>
-<?php 
+    // Present the person information in the view
+    $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => '',
+        'fieldLabel' => __d('field','name'),
+        'groupmember' => $vv_selected_person
+      ]
+    ]);
   } else {
     // Produce the autocomplete people selector on 'add'
-    print $this->Field->peopleAutocompleteControl('person_id', [
-      'for' => 'GroupMembers',
-      'action' => $vv_action,
-      'groupId' => $this->getRequest()?->getQuery('group_id')
-    ]); 
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'person_id',
+        'fieldOptions' => [
+          'class' => 'form-control people-autocomplete',
+          'placeholder' => __d('operation','autocomplete.people.placeholder'),
+          'id' => 'person_id',
+        ],
+        'autocomplete' => [
+          'configuration' => [
+            'for' => 'GroupMembers',
+            'action' => $vv_action,
+            'groupId' => $this->getRequest()?->getQuery('group_id')
+          ]
+        ]
+      ]
+    ]);
   }
-  
-  // XXX As a temporary hack for development, we accept a manually entered Person ID
-  // XXX leave here temporarily.
-  //print $this->Field->control('person_id', ['type' => 'text']);
 } else {
-  print $this->Form->hidden('person_id');
+  $hidden = [
+    'person_id' => $vv_obj->person_id
+  ];
 }
 
-print $this->Field->dateControl('valid_from');
+print $this->element('form/listItem', [
+  'arguments' => [
+    'fieldName' => 'valid_from',
+  ]
+]);
 
-print $this->Field->dateControl('valid_through');
+print $this->element('form/listItem', [
+  'arguments' => [
+    'fieldName' => 'valid_through',
+  ]
+]);
 
 // XXX RFE: Add links to EIS or Nesting info
\ No newline at end of file
diff --git a/app/templates/GroupNestings/fields.inc b/app/templates/GroupNestings/fields.inc
index f913a1f21..673e5b005 100644
--- a/app/templates/GroupNestings/fields.inc
+++ b/app/templates/GroupNestings/fields.inc
@@ -26,22 +26,47 @@
  */
 
 if($vv_action == 'add') {
-  print $this->Field->control('target_group_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'target_group_id',
+    ]
+  ]);
 } elseif($vv_action == 'edit') {
+  $link = [
+    'url' => [
+      'controller' => 'groups',
+      'action'     => 'edit',
+      $vv_obj->target_group_id]
+  ];
   // The target group can't be changed after adding
-  print $this->Field->statusControl('target_group_id',
-                                    $vv_obj->target_group->name, 
-                                    ['url' => ['controller' => 'groups',
-                                               'action'     => 'edit',
-                                               $vv_obj->target_group_id]]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'target_group_id',
+      'status' => $vv_obj->target_group->name,
+      'link' => $link,
+    ]
+  ]);
 }
   
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->statusControl('group_id',
-                                    $vv_bc_parent_obj->name, 
-                                    ['url' => ['controller' => 'groups',
-                                               'action'     => 'edit',
-                                               $vv_bc_parent_obj->id]]);
-  
-  print $this->Field->control('negate');
+  $link = [
+    'url' => [
+      'controller' => 'groups',
+      'action'     => 'edit',
+      $vv_bc_parent_obj->id]
+  ];
+  // The target group can't be changed after adding
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'group_id',
+      'status' => $vv_bc_parent_obj->name,
+      'link' => $link,
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'negate',
+    ]
+  ]);
 }
\ No newline at end of file
diff --git a/app/templates/Groups/fields.inc b/app/templates/Groups/fields.inc
index 6669ba563..fb408df14 100644
--- a/app/templates/Groups/fields.inc
+++ b/app/templates/Groups/fields.inc
@@ -32,50 +32,53 @@ if($vv_obj->isOwners()) {
   $options['readonly'] = true;
 }
 
-print $this->Field->control(
-  fieldName: 'name',
-  options: $options
-);
-
-print $this->Field->control(
-  fieldName: 'description',
-  options: $options
-);
-
-print $this->Field->control(
-  fieldName: 'status',
-  options: $options
-);
-
-print $this->Field->control(
-  fieldName: 'open',
-  options: $options
-);
+foreach(['name',
+          'description',
+          'status',
+          'open',] as $field) {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => $field,
+      'fieldOptions' => $options
+    ]
+  ]);
+}
 
-print $this->Field->control('nesting_mode_all');
+print $this->element('form/listItem', [
+  'arguments' => [
+    'fieldName' => 'nesting_mode_all',
+  ]
+]);
 
 if($vv_action != 'add') {
-  print $this->Field->control(
-    fieldName: 'group_type',
-    options: ['readonly' => true]
-  );
-  
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'group_type',
+      'fieldOptions' => [
+        'readonly' => true
+      ]
+    ]
+  ]);
+
   if($vv_obj->isOwners()) {
     // Link to the main group
     if(!empty($vv_obj->owners_for_group)) {
-      print $this->Field->statusControl(
-        fieldName: 'owners_group_id',
-        status: $vv_obj->owners_for_group->name,
-        link: ['url' => ['controller' => 'groups', 'action' => 'edit', $vv_obj->owners_for_group->id]]
-      );
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'owners_group_id',
+          'status' => $vv_obj->owners_for_group->name,
+          'link' => ['url' => ['controller' => 'groups', 'action' => 'edit', $vv_obj->owners_for_group->id]],
+        ]
+      ]);
     }
   } else {
     // Link to the owners group
-
-    print $this->Field->statusControl(
-      fieldName: 'owners_group_id',
-      status: $vv_obj->owners_group->name ?? '',
-      link: ['url' => ['controller' => 'groups', 'action' => 'edit', $vv_obj->owners_group_id]]
-    );
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'owners_group_id',
+        'status' => $vv_obj->owners_group->name ?? '',
+        'link' => ['url' => ['controller' => 'groups', 'action' => 'edit', $vv_obj->owners_group_id]]
+      ]
+    ]);
   }
 }
diff --git a/app/templates/HistoryRecords/fields.inc b/app/templates/HistoryRecords/fields.inc
index 45c57a180..2bc8d628c 100644
--- a/app/templates/HistoryRecords/fields.inc
+++ b/app/templates/HistoryRecords/fields.inc
@@ -27,7 +27,10 @@
 
 // This view does not support edit
 if($vv_action == 'add' || $vv_action == 'view') {
-  print $this->Field->control('comment');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'comment',
+    ]]);
   
   if($vv_action == 'add') {
     // On manual add insert action
@@ -39,7 +42,10 @@ if($vv_action == 'add' || $vv_action == 'view') {
   }
   
   if($vv_action == 'view') {
-    print $this->Field->control('action');
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'action',
+      ]]);
     
     if(!empty($vv_obj->person->primary_name)) {
       $viewLink = [
@@ -49,12 +55,14 @@ if($vv_action == 'add' || $vv_action == 'view') {
           $vv_obj->person->id
         ],
       ];
-      
-      print $this->Field->statusControl(
-        'person_id',
-        $vv_obj->person->primary_name->full_name,
-        $viewLink
-      );
+
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'person_id',
+          'status' => $vv_obj->person->primary_name->full_name,
+          'link' => $viewLink
+        ]
+      ]);
     }
     
     if(!empty($vv_obj->person_role_id)) {
@@ -65,12 +73,14 @@ if($vv_action == 'add' || $vv_action == 'view') {
           $vv_obj->person_role_id
         ],
       ];
-      
-      print $this->Field->statusControl(
-        'person_role_id',
-        $vv_obj->person_role_id,
-        $viewLink
-      );
+
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'person_role_id',
+          'status' => $vv_obj->person_role_id,
+          'link' => $viewLink
+        ]
+      ]);
     }
     
     if(!empty($vv_obj->external_identity->primary_name)) {
@@ -81,12 +91,14 @@ if($vv_action == 'add' || $vv_action == 'view') {
           $vv_obj->external_identity->id
         ],
       ];
-      
-      print $this->Field->statusControl(
-        'external_identity_id',
-        $vv_obj->external_identity->primary_name->full_name,
-        $viewLink
-      );
+
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'external_identity_id',
+          'status' => $vv_obj->external_identity->primary_name->full_name,
+          'link' => $viewLink
+        ]
+      ]);
     }
     
     if(!empty($vv_obj->external_identity_role_id)) {
@@ -97,12 +109,14 @@ if($vv_action == 'add' || $vv_action == 'view') {
           $vv_obj->external_identity_role_id
         ],
       ];
-      
-      print $this->Field->statusControl(
-        'external_identity_role_id',
-        $vv_obj->external_identity_role_id,
-        $viewLink
-      );
+
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'external_identity_role_id',
+          'status' => $vv_obj->external_identity_role_id,
+          'link' => $viewLink
+        ]
+      ]);
     }
     
     if(!empty($vv_obj->group_id)) {
@@ -113,12 +127,14 @@ if($vv_action == 'add' || $vv_action == 'view') {
           $vv_obj->group_id
         ],
       ];
-      
-      print $this->Field->statusControl(
-        'group_id',
-        $vv_obj->group->name,
-        $viewLink
-      );
+
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'group_id',
+          'status' => $vv_obj->group->name,
+          'link' => $viewLink
+        ]
+      ]);
     }
     
     if(!empty($vv_obj->actor_person->names)) {
@@ -129,15 +145,20 @@ if($vv_action == 'add' || $vv_action == 'view') {
           $vv_obj->actor_person->id
         ],
       ];
-      
-      print $this->Field->statusControl(
-        'actor_person_id',
-        $vv_obj->actor_person->names[0]->full_name,
-        $viewLink,
-        __d('field', 'actor')
-      );
+
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'actor_person_id',
+          'status' => $vv_obj->actor_person->names[0]->full_name,
+          'link' => $viewLink,
+          'fieldLabel' => __d('field', 'actor')
+        ]
+      ]);
     }
-    
-    print $this->Field->control('created');
+
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'created',
+      ]]);
   }
 }
diff --git a/app/templates/IdentifierAssignments/fields.inc b/app/templates/IdentifierAssignments/fields.inc
index 864157b9b..93ca8e381 100644
--- a/app/templates/IdentifierAssignments/fields.inc
+++ b/app/templates/IdentifierAssignments/fields.inc
@@ -1,6 +1,6 @@
 <?php
 /**
- * COmanage Registry Identifier Assignment Fields
+ * COmanage Registry Identifier Assignments Fields
  *
  * Portions licensed to the University Corporation for Advanced Internet
  * Development, Inc. ("UCAID") under one or more contributor license agreements.
@@ -56,7 +56,10 @@
   }
 
   function resetType(id) {
-    document.getElementById(id).value = "";
+    const dropDown = document.getElementById(id);
+    dropDown.value = "";
+    dropDown.selectedIndex = 0;
+
     updateGadgets();
   }
 
@@ -68,41 +71,57 @@
 <?php
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('description');
+  foreach([
+            'description',
+            'status',
+            'plugin'
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]]);
+  }
 
-  print $this->Field->control('status');
-  
-  print $this->Field->control('plugin');
-  
-  print $this->Field->control(
-    fieldName: 'context',
-    options: [
-      'onChange' => 'updateGadgets()'
-    ]
-  );
-  
-  print $this->Field->control(
-    fieldName: 'identifier_type_id',
-    options: [
-      'onChange' => 'resetType("email-address-type-id")'
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'context',
+      'fieldOptions' => [
+        'onChange' => 'updateGadgets()'
+      ]
     ]
-  );
-  
-  print $this->Field->control(
-    fieldName: 'login',
-    cssClass: 'subfield'
-  );
+  ]);
 
-  print $this->Field->control(
-    fieldName: 'email_address_type_id',
-    options: [
-      'onChange' => 'resetType("identifier-type-id")'
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'identifier_type_id',
+      'fieldOptions' => [
+        'onChange' => 'resetType("email-address-type-id")'
+      ]
     ]
-  );
+  ]);
 
-  print $this->Field->control('group_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'login'
+    ]
+  ]);
 
-  print $this->Field->control('allow_empty');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'email_address_type_id',
+      'fieldOptions' => [
+        'onChange' => 'resetType("identifier-type-id")'
+      ]
+    ]
+  ]);
 
-  print $this->Field->control('ordr');
+  foreach(['group_id',
+           'allow_empty',
+           'ordr'
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]]);
+  }
 }
\ No newline at end of file
diff --git a/app/templates/Identifiers/fields.inc b/app/templates/Identifiers/fields.inc
index 532f29865..5d0b03a34 100644
--- a/app/templates/Identifiers/fields.inc
+++ b/app/templates/Identifiers/fields.inc
@@ -26,20 +26,45 @@
  */
 
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
-  print $this->Field->control('identifier');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'identifier',
+    ]]);
 
-  print $this->Field->control('type_id', ['default' => $vv_default_type]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_type
+      ]
+    ]]);
 
   if($vv_primary_link_attr == 'person_id') {
     // AR-Identifier-1 Only Persons can have a login flag
-    print $this->Field->control('login');
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'login',
+      ]]);
   } else {
+    // Will be used by add-edit-view.php to append the hidden fields in the form
     $hidden['login'] = false;
   }
-  
-  print $this->Field->control('status', ['empty' => false]);
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status',
+    ]]);
 
-  print $this->Field->sourceControl($vv_obj);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
+}
+
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
 }
diff --git a/app/templates/JobHistoryRecords/fields.inc b/app/templates/JobHistoryRecords/fields.inc
index ea26401a1..f742fcdaf 100644
--- a/app/templates/JobHistoryRecords/fields.inc
+++ b/app/templates/JobHistoryRecords/fields.inc
@@ -27,11 +27,16 @@
 
 // This view does not support add or edit
 if($vv_action == 'view') {
-  print $this->Field->control('record_key');
-  
-  print $this->Field->control('comment');
-  
-  print $this->Field->control('status');
+  foreach(['record_key',
+           'comment',
+           'status'
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 
 // Rewrite these to always emit the column even if the field is blank
   if(!empty($vv_obj->person->primary_name)) {
@@ -42,12 +47,14 @@ if($vv_action == 'view') {
         $vv_obj->person->id
       ],
     ];
-    
-    print $this->Field->statusControl(
-      'person_id',
-      $vv_obj->person->primary_name->full_name,
-      $viewLink
-    );
+
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'person_id',
+        'status' => $vv_obj->person->primary_name->full_name,
+        'link' => $viewLink,
+      ]
+    ]);
   }
   
   if(!empty($vv_obj->external_identity->primary_name)) {
@@ -58,13 +65,19 @@ if($vv_action == 'view') {
         $vv_obj->external_identity->id
       ],
     ];
-    
-    print $this->Field->statusControl(
-      'external_identity_id',
-      $vv_obj->external_identity->primary_name->full_name,
-      $viewLink
-    );
+
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'external_identity_id',
+        'status' => $vv_obj->external_identity->primary_name->full_name,
+        'link' => $viewLink,
+      ]
+    ]);
   }
 
-  print $this->Field->control('created');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'created'
+    ]
+  ]);
 }
diff --git a/app/templates/Jobs/fields.inc b/app/templates/Jobs/fields.inc
index 238a9da85..bd6d9f1a7 100644
--- a/app/templates/Jobs/fields.inc
+++ b/app/templates/Jobs/fields.inc
@@ -1,6 +1,6 @@
 <?php
 /**
- * COmanage Registry Jobs Fields
+ * COmanage Registry Job History Records Fields
  *
  * Portions licensed to the University Corporation for Advanced Internet
  * Development, Inc. ("UCAID") under one or more contributor license agreements.
@@ -27,78 +27,69 @@
 
 // This view does not support add or edit
 if($vv_action == 'view') {
-  print $this->Field->control('plugin', labelText: __d('controller', 'Jobs', [1]));
-  
-  print $this->Field->control('status');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'plugin',
+      'fieldLabel' => __d('controller', 'Jobs', [1])
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status'
+    ]
+  ]);
 
   if($vv_obj->status == \App\Lib\Enum\JobStatusEnum::InProgress) {
-    print $this->Field->statusControl(
-      fieldName: 'percent_complete',
-      status: (string)$vv_obj->percent_complete
-    );
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'percent_complete',
+        'status' => (string)$vv_obj->percent_complete
+      ]
+    ]);
   }
-  
-  $beforeField = '
-    <div class="field-suppliment">
-      <div class="form-check">
-        <input class="form-check-input" type="checkbox" value="" id="format-toggle">
-        <label class="form-check-label" for="format-toggle">' .
-          __d('field','format')
-        . '</label>
-      </div>
-    </div>
-  ';
-  $afterField = '
-    <script>
-      parametersValue = $("#parameters").val();
-      parametersJSON = JSON.parse(parametersValue);
-      $("#format-toggle").click(function() {
-        if($(this).is(":checked")) {         
-          $("#parameters").val(JSON.stringify(parametersJSON, null, 4));
-          paramsHeight = Object.keys(parametersJSON).length + 6 + "em";
-          $("#parameters").css("height",paramsHeight);
-        } else {
-          $("#parameters").val(parametersValue);
-          $("#parameters").css("height","4em");
-        }
-      });
-    </script>
-  ';
-  print $this->Field->control('parameters', beforeField: $beforeField, afterField: $afterField);
-
-  print $this->Field->control('register_time');
-
-  print $this->Field->control('register_summary');
-
-  print $this->Field->control('assigned_host');
-
-  print $this->Field->control('assigned_pid');
-
-  print $this->Field->control('start_after_time');
 
-  print $this->Field->control('start_time');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'parameters',
+      'check' => true
+    ]
+  ]);
 
-  print $this->Field->control('start_summary');
-
-  print $this->Field->control('finish_time');
-
-  print $this->Field->control('finish_summary');
-
-  print $this->Field->control('requeue_interval');
-
-  print $this->Field->control('retry_interval');
+  foreach([
+            'register_time',
+            'register_summary',
+            'assigned_host',
+            'assigned_pid',
+            'start_after_time',
+            'start_time',
+            'start_summary',
+            'finish_time',
+            'finish_summary',
+            'requeue_interval',
+            'retry_interval',
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 
   if(!empty($vv_obj->requeued_from_job->id)) {
-    print $this->Field->statusControl(
-      fieldName: 'requeued_from_job_id',
-      status: (string)$vv_obj->requeued_from_job->id,
-      link: [
-        'url' => [
-          'controller'  => 'jobs',
-          'action'      => 'view',
-          $vv_obj->requeued_from_job->id
-        ]
+    $link = [
+      'url' => [
+        'controller'  => 'jobs',
+        'action'      => 'view',
+        $vv_obj->requeued_from_job->id
+      ]
+    ];
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'requeued_from_job_id',
+        'status' => (string)$vv_obj->requeued_from_job->id,
+        'link' => $link,
       ]
-    );
+    ]);
   }
 }
diff --git a/app/templates/MessageTemplates/fields.inc b/app/templates/MessageTemplates/fields.inc
index c52d7e61b..a88f5e691 100644
--- a/app/templates/MessageTemplates/fields.inc
+++ b/app/templates/MessageTemplates/fields.inc
@@ -28,25 +28,23 @@
 <?php
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('description');
-
-  print $this->Field->control('status');
-
-  print $this->Field->control('context');
-
-  print $this->Field->control('format');
-
-  print $this->Field->control('subject');
-
+  foreach ([
+             'description',
+             'status',
+             'context',
+             'format',
+             'subject',
 // XXX auto show/hide based on format
-  print $this->Field->control('body_text');
-
+             'body_text',
 // XXX auto show/hide based on format
-  print $this->Field->control('body_html');
-
-  print $this->Field->control('cc');
-
-  print $this->Field->control('bcc');
-
-  print $this->Field->control('reply_to');
+             'body_html',
+             'cc',
+             'bcc',
+             'reply_to',
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
 }
diff --git a/app/templates/Names/fields.inc b/app/templates/Names/fields.inc
index 3b16e5804..f4a19b41d 100644
--- a/app/templates/Names/fields.inc
+++ b/app/templates/Names/fields.inc
@@ -31,22 +31,54 @@ if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
 
   foreach(['honorific', 'given', 'middle', 'family', 'suffix'] as $f) {
     if(in_array($f, $vv_permitted_fields)) {
-      print $this->Field->control($f);
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => $f
+        ]]);
     }
   }
 
-  print $this->Field->control('type_id', ['default' => $vv_default_type]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_type
+      ]
+    ]]);
 
-  print $this->Field->control('language');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'language'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'display_name'
+    ]]);
 
-  print $this->Field->control('display_name');
   
   // We don't allow unsetting of primary_name here because we need to know what
   // the new primary_name is, but we do allow this name to become primary
   // because afterSave will unset the old one.
-  print $this->Field->control('primary_name', ['readonly' => $vv_obj->primary_name]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'description',
+      'fieldOptions' => [
+        'readonly' => $vv_obj->primary_name
+      ]
+    ]]);
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
 
-  print $this->Field->sourceControl($vv_obj);
 }
+
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
+}
\ No newline at end of file
diff --git a/app/templates/Notifications/fields.inc b/app/templates/Notifications/fields.inc
index 6409a736c..c6a5819bd 100644
--- a/app/templates/Notifications/fields.inc
+++ b/app/templates/Notifications/fields.inc
@@ -30,96 +30,109 @@ use \App\Lib\Enum\NotificationStatusEnum;
 <?php
 // This view does not support add or edit
 if($vv_action == 'view') {
-  print $this->Field->control('comment');
-
-  print $this->Field->control('action');
-
-  print $this->Field->control('source');
-
-  print $this->Field->control('created');
+  foreach ([
+             'comment',
+             'action',
+             'source',
+             'created',
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
 
   if($vv_obj->status == NotificationStatusEnum::PendingAcknowledgment) {
-    print $this->Field->statusControl(
-      fieldName:  'status',
-      status:     __d('enumeration', 'NotificationStatusEnum.PA'),
-      link:       [
-                    'url' => [
-                      'action' => 'acknowledge',
-                      $vv_obj->id
-                    ],
-                    'label' => __d('operation', 'acknowledge'),
-                    'confirm' => __d('operation', 'Notifications.acknowledge.confirm')
-                  ]
-    );
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'status',
+        'status'    => __d('enumeration', 'NotificationStatusEnum.PA'),
+        'link'      => [
+                        'url' => [
+                          'action' => 'acknowledge',
+                          $vv_obj->id
+                        ],
+                        'label' => __d('operation', 'acknowledge'),
+                        'confirm' => __d('operation', 'Notifications.acknowledge.confirm')
+                      ]
+      ]
+    ]);
   } else {
     print $this->Field->control('status');
-  }  
-
-  print $this->Field->statusControl(
-    fieldName:  'subject_person_id',
-    status:     !empty($vv_obj->subject_person->primary_name)
-                ? $vv_obj->subject_person->primary_name->full_name
-                : "",
-    link:       !empty($vv_obj->subject_person)
-                ? ['url' => [
-                    'controller' => 'people',
-                    'action' => 'edit',
-                    $vv_obj->subject_person->id
-                  ]]
-                : []
-  );
-
-  print $this->Field->statusControl(
-    fieldName:  'recipient_person_id',
-    status:     !empty($vv_obj->recipient_person->primary_name)
-                ? $vv_obj->recipient_person->primary_name->full_name
-                : "",
-    link:       !empty($vv_obj->recipient_person)
-                ? ['url' => [
-                    'controller' => 'people',
-                    'action' => 'edit',
-                    $vv_obj->recipient_person->id
-                  ]]
-                : []
-  );
-
-  print $this->Field->statusControl(
-    fieldName:  'actor_person_id',
-    status:     !empty($vv_obj->actor_person->primary_name)
-                ? $vv_obj->actor_person->primary_name->full_name
-                : "",
-    link:       !empty($vv_obj->actor_person)
-                ? ['url' => [
-                    'controller' => 'people',
-                    'action' => 'edit',
-                    $vv_obj->actor_person->id
-                  ]]
-                : []
-  );
-
-  print $this->Field->control('resolution_time');
+  }
 
-  print $this->Field->statusControl(
-    fieldName:  'resolver_person_id',
-    status:     !empty($vv_obj->resolver_person->primary_name)
-                ? $vv_obj->resolver_person->primary_name->full_name
-                : "",
-    link:       !empty($vv_obj->resolver_person)
-                ? ['url' => [
-                    'controller' => 'people',
-                    'action' => 'edit',
-                    $vv_obj->resolver_person->id
-                  ]]
-                : []
-  );
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'subject_person_id',
+      'status'    => $vv_obj->subject_person->primary_name?->full_name ?? '',
+      'link'      => !empty($vv_obj->subject_person)
+                     ? ['url' => [
+                       'controller' => 'people',
+                       'action' => 'edit',
+                       $vv_obj->subject_person->id
+                     ]]
+                     : []
+    ]
+  ]);
 
-  print $this->Field->control('notification_time');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'recipient_person_id',
+      'status'    => $vv_obj->recipient_person->primary_name?->full_name ?? '',
+      'link'      => !empty($vv_obj->recipient_person)
+                     ? ['url' => [
+                       'controller' => 'people',
+                       'action' => 'edit',
+                       $vv_obj->recipient_person->id
+                     ]]
+                     : []
+    ]
+  ]);
 
-  print $this->Field->control('email_subject');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'actor_person_id',
+      'status'    => $vv_obj->actor_person->primary_name?->full_name ?? '',
+      'link'      => !empty($vv_obj->actor_person)
+                     ? ['url' => [
+                       'controller' => 'people',
+                       'action' => 'edit',
+                       $vv_obj->actor_person->id
+                     ]]
+                     : []
+    ]
+  ]);
 
-  print $this->Field->control('email_body_text');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'resolution_time',
+    ]
+  ]);
 
-  print $this->Field->control('resolution_subject');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'resolver_person_id',
+      'status'    => $vv_obj->resolver_person->primary_name?->full_name ?? '',
+      'link'      => !empty($vv_obj->resolver_person)
+                     ? ['url' => [
+                       'controller' => 'people',
+                       'action' => 'edit',
+                       $vv_obj->resolver_person->id
+                     ]]
+                     : []
+    ]
+  ]);
 
-  print $this->Field->control('resolution_body');
+  foreach ([
+             'notification_time',
+             'email_subject',
+             'email_body_text',
+             'resolution_subject',
+             'resolution_body',
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
 }
diff --git a/app/templates/People/fields.inc b/app/templates/People/fields.inc
index dee3cd5be..016c50412 100644
--- a/app/templates/People/fields.inc
+++ b/app/templates/People/fields.inc
@@ -33,19 +33,25 @@ if($vv_action == 'add') {
   
   foreach(['honorific', 'given', 'middle', 'family', 'suffix'] as $f) {
     if(in_array($f, $vv_permitted_name_fields)) {
-      print $this->Field->control(
-        fieldName: 'names.0.'.$f,
-        options: ['required' => in_array($f, $vv_required_name_fields)],
-        controlType: 'string'
-      );
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => 'names.0.'.$f,
+          'fieldOptions' => [
+            'required' => in_array($f, $vv_required_name_fields)
+          ],
+          'fieldType' => 'string'
+        ]]);
     }
   }
-  
-  print $this->Field->control(
-    fieldName: 'names.0.type_id',
-    options: ['empty' => false, 'default' => $vv_default_name_type],
-    controlType: 'string'
-  );
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'names.0.type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_name_type
+      ],
+      'fieldType' => 'string'
+    ]]);
   
   // AR-Name-1 Since this is the first name for this Person, it must be
   // designated primary
@@ -58,7 +64,13 @@ if($vv_action == 'add') {
 }
 
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('status', ['empty' => false]);
-  
-  print $this->Field->dateControl('date_of_birth', \App\Lib\Enum\DateTypeEnum::DateOnly);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'date_of_birth'
+    ]]);
 }
\ No newline at end of file
diff --git a/app/templates/PersonRoles/fields.inc b/app/templates/PersonRoles/fields.inc
index 4748921f3..3a103add4 100644
--- a/app/templates/PersonRoles/fields.inc
+++ b/app/templates/PersonRoles/fields.inc
@@ -26,19 +26,35 @@
  */
 
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
-  print $this->Field->control('cou_id');
-  
-  print $this->Field->control('affiliation_type_id', labelText: __d('field', 'affiliation'));
-  
-  print $this->Field->control('status', ['empty' => false]);
-  
-  print $this->Field->control('ordr');
-  
-  print $this->Field->control('title');
-  
-  print $this->Field->control('organization');
-  
-  print $this->Field->control('department');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'cou_id',
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' =>'affiliation_type_id',
+      'fieldLabel' => __d('field', 'affiliation')
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' =>'status'
+    ]
+  ]);
+
+  foreach(['ordr',
+           'title',
+           'organization',
+           'department'] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
   
   // For now, we render sponsor and manager as read only.
   // XXX Need People Picker (CFM-150)
@@ -52,15 +68,39 @@ if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
       $fname = $vv_obj->$fp->names[0]->full_name;
       $flink = ['url' => ['controller' => 'people', 'action' => 'edit', $vv_obj->$fp->id]];
     }
-    
-    print $this->Field->statusControl($f.'_person_id', $fname, $flink, __d('field', $f));
+
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $f.'_person_id',
+        'status' => $fname,
+        'link' => $flink,
+        'fieldLabel' => __d('field', $f)
+      ]
+    ]);
   }
-  
-  print $this->Field->dateControl('valid_from');
-  
-  print $this->Field->dateControl('valid_through');
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'valid_from', // timestamp
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'valid_through', // timestamp
+    ]
+  ]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
+}
 
-  print $this->Field->sourceControl($vv_obj);
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
 }
diff --git a/app/templates/Pipelines/fields.inc b/app/templates/Pipelines/fields.inc
index e4efd0ca2..58a956008 100644
--- a/app/templates/Pipelines/fields.inc
+++ b/app/templates/Pipelines/fields.inc
@@ -50,37 +50,46 @@
 <?php
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('description');
-
-  print $this->Field->control('status');
-  
-  // Match Strategy
-  print $this->Field->control(
-    fieldName: 'match_strategy',
-    controlType: 'select',
-    options: [
-      'onChange' => 'updateGadgets()'
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'description'
     ]
-  );
-
-  print $this->Field->control('match_email_address_type_id');
-
-  print $this->Field->control('match_identifier_type_id');
-
-  // Sync Strategy
-//  print $this->Field->control('sync_on_update');
-
-//  print $this->Field->control('sync_on_delete');
+  ]);
 
-  print $this->Field->control('sync_status_on_delete', ['empty' => false]);
-
-  print $this->Field->control('sync_cou_id');
-
-  print $this->Field->control('sync_replace_cou_id');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status'
+    ]
+  ]);
 
-  print $this->Field->control('sync_affiliation_type_id');
+  // Match Strategy
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'match_strategy',
+      'fieldOptions' => [
+        'onChange' => 'updateGadgets()'
+      ],
+      'fieldType' => 'select'
+    ]
+  ]);
 
-  print $this->Field->control('sync_identifier_type_id');
+  foreach([
+            'match_email_address_type_id',
+            'match_identifier_type_id',
+//            'sync_on_update',
+//            'sync_on_delete',
+            'sync_status_on_delete',
+            'sync_cou_id',
+            'sync_replace_cou_id',
+            'sync_affiliation_type_id',
+            'sync_identifier_type_id',
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field,
+      ]
+    ]);
+  }
 
   // Connections
 //XXX
diff --git a/app/templates/Pronouns/fields.inc b/app/templates/Pronouns/fields.inc
index a5361fc5e..0104a3b7f 100644
--- a/app/templates/Pronouns/fields.inc
+++ b/app/templates/Pronouns/fields.inc
@@ -26,13 +26,34 @@
  */
 
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
-  print $this->Field->control('pronouns');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'pronouns'
+    ]]);
 
-  print $this->Field->control('type_id', ['default' => $vv_default_type]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_type
+      ]
+    ]]);
 
-  print $this->Field->control('language');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'language'
+    ]]);
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
+}
 
-  print $this->Field->sourceControl($vv_obj);
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
 }
diff --git a/app/templates/ProvisioningHistoryRecords/fields.inc b/app/templates/ProvisioningHistoryRecords/fields.inc
index d6b9ca9ec..027766e58 100644
--- a/app/templates/ProvisioningHistoryRecords/fields.inc
+++ b/app/templates/ProvisioningHistoryRecords/fields.inc
@@ -27,9 +27,15 @@
 
 // This view does not support add or edit
 if($vv_action == 'view') {
-  print $this->Field->control('comment');
-  
-  print $this->Field->control('status');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'comment'
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status'
+    ]]);
 
   // Currently these records only apply to People and Groups, but that will probably change
   if(!empty($vv_obj->person->primary_name)) {
@@ -40,29 +46,41 @@ if($vv_action == 'view') {
         $vv_obj->person->id
       ],
     ];
-    
-    print $this->Field->statusControl(
-      'person_id',
-      $vv_obj->person->primary_name->full_name,
-      $viewLink
-    );
+
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'person_id',
+        'status' => $vv_obj->person->primary_name->full_name,
+        'link' => $viewLink,
+      ]
+    ]);
   } else {
-    print $this->Field->statusControl(
-      'group_id',
-      $vv_obj->group->name,
-      [
-        'url' => [
-          'controller'  => 'groups',
-          'action'      => 'edit',
-          $vv_obj->group->id
-        ]
+    $viewLink = [
+      'url' => [
+        'controller'  => 'groups',
+        'action'      => 'edit',
+        $vv_obj->group->id
       ]
-    );
-  }
+    ];
 
-  print $this->Field->control('subject_model');
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => 'group_id',
+        'status' => $vv_obj->group->name,
+        'link' => $viewLink,
+      ]
+    ]);
+  }
 
-  print $this->Field->control('subjectid');
-  
-  print $this->Field->control('created');
+  foreach([
+            'subject_model',
+            'subjectid',
+            'created',
+          ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]
+    ]);
+  }
 }
diff --git a/app/templates/ProvisioningTargets/fields.inc b/app/templates/ProvisioningTargets/fields.inc
index fd4ed02cf..1e3b025de 100644
--- a/app/templates/ProvisioningTargets/fields.inc
+++ b/app/templates/ProvisioningTargets/fields.inc
@@ -49,28 +49,41 @@ alert("Queue modes not yet implemented"); // XXX CFM-26
 <?php
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('description');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'description'
+    ]]);
 
-  print $this->Field->control(
-    fieldName: 'status', 
-    options: [
-      'onChange' => 'updateGadgets()',
-      'default'  => \App\Lib\Enum\ProvisionerModeEnum::QueueOnError
-    ]
-  );
-  
-  print $this->Field->control(
-    fieldName: 'retry_interval', 
-    options: [
-      'default' => 900
-    ],
-    cssClass: 'subfield'
-  );
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'status',
+      'fieldOptions' => [
+        'onChange' => 'updateGadgets()',
+        'default'  => \App\Lib\Enum\ProvisionerModeEnum::QueueOnError
+      ]
+    ]]);
 
-  print $this->Field->control('plugin');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'retry_interval',
+      'fieldOptions' => [
+        'default' => 900
+      ]
+    ]]);
 
-// Not yet implemented (CFM-26)
-//  print $this->Field->control('provisioning_group_id');
-  
-  print $this->Field->control('ordr');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'plugin'
+    ]]);
+
+//  // todo: Not yet implemented (CFM-26)
+//  print $this->element('form/listItem', [
+//    'arguments' => [
+//      'fieldName' => 'provisioning_group_id'
+//    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'ordr'
+    ]]);
 }
diff --git a/app/templates/ProvisioningTargets/status.php b/app/templates/ProvisioningTargets/status.php
index 6df0f712a..b22ac3d26 100644
--- a/app/templates/ProvisioningTargets/status.php
+++ b/app/templates/ProvisioningTargets/status.php
@@ -40,13 +40,13 @@
 
   <?php if(!empty($indexBanners)): ?>
     <?php foreach($indexBanners as $b): ?>
-      <?=  $this->Alert->alert($b, 'warning') ?>
+      <?= $this->element('notify/alert', ['message' => $b]) ?>
     <?php endforeach; // $indexBanners ?>
   <?php endif; // $indexBanners ?>
 
   <?php if(!empty($banners)): ?>
     <?php foreach($banners as $b): ?>
-      <?= $this->Alert->alert($b, 'warning') ?>
+      <?= $this->element('notify/alert', ['message' => $b]) ?>
     <?php endforeach; // $banners ?>
   <?php endif; // $banners ?>
 </div>
diff --git a/app/templates/Servers/fields.inc b/app/templates/Servers/fields.inc
index ea9c1e85d..0e27460e0 100644
--- a/app/templates/Servers/fields.inc
+++ b/app/templates/Servers/fields.inc
@@ -28,9 +28,14 @@
 <?php
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control('description');
+  foreach (['description',
+             'status',
+             'plugin'
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
 
-  print $this->Field->control('status');
-  
-  print $this->Field->control('plugin');
 }
diff --git a/app/templates/Standard/add-edit-view.php b/app/templates/Standard/add-edit-view.php
index e0afbbd7a..bce04253c 100644
--- a/app/templates/Standard/add-edit-view.php
+++ b/app/templates/Standard/add-edit-view.php
@@ -176,10 +176,6 @@
 <?php endif; ?>
 
 <?php
-// By default, the form will POST to the current controller
-// Note we need to open the form for view so Cake will autopopulate values
-print $this->Form->create($vv_obj);
-
 $linkId = null;
 
 if(!empty($vv_primary_link)) {
@@ -192,52 +188,29 @@
   }
 }
 
-print $this->Field->startControlSet(
-  modelName: $this->name,
-  action: $vv_action,
-  // XXX We need a model specific mechanism to disable read-only
-  editable: ($vv_action == 'add' || $vv_action == 'edit'),
-  reqFields: $vv_required_fields,
-  pluginName: $this->getPlugin()
-);
-
-// We allow the fields.inc file to be specified for Controllers that have more
-// complicated/non-default actions.
-$fieldsFile = "fields.inc";
-
-if(!empty($vv_fields_inc)) {
-  $fieldsFile = $vv_fields_inc;
-}
-
-// The controller will calculate the template path for us, since it could be
-// in one of several paths if we are in a plugin context.
-include($vv_template_path . DS . $fieldsFile);
+/*
+ * Views have a set() method that is analogous to the set() found in Controller objects.
+ * Using set() from your view file will add the variables to the layout and elements
+ * that will be rendered later.
+ */
 
-if(!empty($hidden)) {
-  // Inject any hidden variables set by the include file
-  foreach($hidden as $attr => $v) {
-    print $this->Form->hidden($attr, ['value' => $v]);
-  }
-}
+// By default, the form will POST to the current controller
+// Note we need to open the form for view so Cake will autopopulate values
+print $this->Form->create($vv_obj);
 
-if($vv_action != 'add') {
-  print '<li id="cm-entity-id">' . __d('information', 'entity.id', $vv_obj->id) . '</li>';  
-}
+// List of records to collect
+// Form body
+print $this->element('form/unorderedList');
 
-if($vv_action == 'add' || $vv_action == 'edit') {
+if(!empty($linkId)
+   && ($vv_action == 'add' || $vv_action == 'edit')) {
   // We don't want/need to output these for view actions
-  
-  if(!empty($linkId)) {
-    // Hidden values used to link to parent objects (eg: matchgrid_id)
-    print $this->Form->hidden($vv_primary_link, ['value' => $linkId]);
-  }
-  
-  print $this->Field->submit(__d('operation', 'save'));
+  print $this->Form->hidden($vv_primary_link, ['value' => $linkId]);
 }
 
+// Close the Form
 print $this->Form->end();
 
-print $this->Field->endControlSet();
 
 /** MVEA Canvas output **/
 if($vv_action != 'add' && !empty($mveas)) {
diff --git a/app/templates/TelephoneNumbers/fields.inc b/app/templates/TelephoneNumbers/fields.inc
index 2f772914d..fe47db851 100644
--- a/app/templates/TelephoneNumbers/fields.inc
+++ b/app/templates/TelephoneNumbers/fields.inc
@@ -31,15 +31,37 @@ if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
   
   foreach(['country_code', 'area_code', 'number', 'extension'] as $f) {
     if(in_array($f, $vv_permitted_fields)) {
-      print $this->Field->control($f);
+      print $this->element('form/listItem', [
+        'arguments' => [
+          'fieldName' => $f
+        ]]);
     }
   }
-  
-  print $this->Field->control('type_id', ['default' => $vv_default_type]);
 
-  print $this->Field->control('description');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_type
+      ]
+    ]]);
+
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'description'
+    ]]);
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
+
+}
 
-  print $this->Field->sourceControl($vv_obj);
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
 }
diff --git a/app/templates/Types/fields.inc b/app/templates/Types/fields.inc
index 8e89035de..d235049c1 100644
--- a/app/templates/Types/fields.inc
+++ b/app/templates/Types/fields.inc
@@ -48,19 +48,23 @@
 <?php
 // This view does not support read-only
 if($vv_action == 'add' || $vv_action == 'edit') {
-  print $this->Field->control(
-    fieldName: 'attribute', 
-    options: [
-      'onChange' => 'updateGadgets()', 
-      'readonly' => $vv_action == 'edit'
-    ]
-  );
-  
-  print $this->Field->control('display_name');
-  
-  print $this->Field->control('value');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'attribute',
+      'fieldOptions' => [
+        'onChange' => 'updateGadgets()',
+        'readonly' => $vv_action == 'edit'
+      ]
+    ]]);
 
-  print $this->Field->control('status');
-  
-  print $this->Field->control('edupersonaffiliation');
+  foreach (['display_name',
+             'value',
+             'status',
+             'edupersonaffiliation'
+           ] as $field) {
+    print $this->element('form/listItem', [
+      'arguments' => [
+        'fieldName' => $field
+      ]]);
+  }
 }
diff --git a/app/templates/Urls/fields.inc b/app/templates/Urls/fields.inc
index 93ca41f36..4d48a815a 100644
--- a/app/templates/Urls/fields.inc
+++ b/app/templates/Urls/fields.inc
@@ -26,13 +26,34 @@
  */
 
 if($vv_action == 'add' || $vv_action == 'edit' || $vv_action == 'view') {
-  print $this->Field->control('url');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'url'
+    ]]);
 
-  print $this->Field->control('type_id', ['default' => $vv_default_type]);
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'type_id',
+      'fieldOptions' => [
+        'default' => $vv_default_type
+      ]
+    ]]);
 
-  print $this->Field->control('description');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'description'
+    ]]);
 
-  print $this->Field->control('frozen');
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'frozen'
+    ]]);
+}
 
-  print $this->Field->sourceControl($vv_obj);
+if($vv_action == 'edit' || $vv_action == 'view') {
+  print $this->element('form/listItem', [
+    'arguments' => [
+      'fieldName' => 'source',
+      'entity' => $vv_obj
+    ]]);
 }
diff --git a/app/templates/element/filter/dateTimeFilters.php b/app/templates/element/filter/dateTimeFilters.php
index 4c7440dba..fb38f0f50 100644
--- a/app/templates/element/filter/dateTimeFilters.php
+++ b/app/templates/element/filter/dateTimeFilters.php
@@ -42,7 +42,7 @@
           <?php
           // Create a text field to hold our value.
           print $this->Form->label("{$key}_starts_at", __d('field', 'starts_at'), ['class' => 'filter-datepicker-lbl']);
-          print $this->Field->dateField("{$key}_starts_at", DateTypeEnum::DateOnly, $query)['controlCode'];
+          print $this->Field->dateField("{$key}_starts_at", DateTypeEnum::DateOnly, $query);
           ?>
         </div>
         <!--     Ends at       -->
@@ -50,7 +50,7 @@
           <?php
           // Create a text field to hold our value.
           print $this->Form->label("{$key}_ends_at", __d('field','ends_at'), ['class' => 'filter-datepicker-lbl']);
-          print $this->Field->dateField("{$key}_ends_at", DateTypeEnum::DateOnly, $query)['controlCode'];
+          print $this->Field->dateField("{$key}_ends_at", DateTypeEnum::DateOnly, $query);
           ?>
         </div>
       </div>
diff --git a/app/templates/element/filter/filter.php b/app/templates/element/filter/filter.php
index ca534135b..f0df46ea6 100644
--- a/app/templates/element/filter/filter.php
+++ b/app/templates/element/filter/filter.php
@@ -129,7 +129,7 @@
             print '<div class="top-filters-fields-date filter-standard ' . $wrapperCssClass . '">';
             print $this->Form->label($key, $label);
             print '<div class="d-flex">';
-            print $this->Field->dateField($key, DateTypeEnum::DateOnly, $query)['controlCode'];
+            print $this->Field->dateField($key, DateTypeEnum::DateOnly, $query);
             print '</div>';
             print '</div>';
           } else {
diff --git a/app/templates/element/flash.php b/app/templates/element/flash.php
index 5c6a91f26..3809206e3 100644
--- a/app/templates/element/flash.php
+++ b/app/templates/element/flash.php
@@ -32,13 +32,13 @@
   
   <?php if(!empty($vv_index_banners)): ?>
     <?php foreach($vv_index_banners as $b): ?>
-      <?=  $this->Alert->alert($b, 'warning') ?>
+      <?= $this->element('notify/alert', ['message' => $b]) ?>
     <?php endforeach; // $vv_index_banners ?>
   <?php endif; // $vv_index_banners ?>
   
   <?php if(!empty($vv_banners)): ?>
     <?php foreach($vv_banners as $b): ?>
-      <?=  $this->Alert->alert($b, 'warning') ?>
+      <?= $this->element('notify/alert', ['message' => $b]) ?>
     <?php endforeach; // $vv_banners ?>
   <?php endif; // $vv_banners ?>
 </div>
\ No newline at end of file
diff --git a/app/templates/element/flash/default.php b/app/templates/element/flash/default.php
index 325e35513..7484ee14a 100644
--- a/app/templates/element/flash/default.php
+++ b/app/templates/element/flash/default.php
@@ -8,6 +8,6 @@
   <?php /* CFM-221: while a prefix such as "Error: " or "Success: " can be sent with the Alert, 
     we avoid prefixes to better support LTR languages. Prefixes, if desired, should be included 
     directly in the language strings instead. */ ?>
-  <?= $this->Alert->alert($message, 'warning', true) ?>
+  <?= $this->element('notify/alert', ['message' => $message]) ?>
 <?php endif; ?>
 
diff --git a/app/templates/element/flash/error.php b/app/templates/element/flash/error.php
index 8069a15da..c77a0eac9 100644
--- a/app/templates/element/flash/error.php
+++ b/app/templates/element/flash/error.php
@@ -8,5 +8,9 @@
   <?php /* CFM-221: while a prefix such as "Error: " or "Success: " can be sent with the Alert, 
     we avoid prefixes to better support LTR languages. Prefixes, if desired, should be included 
     directly in the language strings instead. */ ?>
-  <?= $this->Alert->alert($message, 'danger', true) ?>
+  <?= $this->element('notify/alert', [
+    'message' => $message,
+    'type' => 'danger',
+    'dismissible' => true
+  ]) ?>
 <?php endif; ?>
diff --git a/app/templates/element/flash/information.php b/app/templates/element/flash/information.php
index 26dc52329..c7b7b83b1 100644
--- a/app/templates/element/flash/information.php
+++ b/app/templates/element/flash/information.php
@@ -8,5 +8,9 @@
   <?php /* CFM-221: while a prefix such as "Error: " or "Success: " can be sent with the Alert, 
     we avoid prefixes to better support LTR languages. Prefixes, if desired, should be included 
     directly in the language strings instead. */ ?>
-  <?= $this->Alert->alert($message, 'information', true) ?>
+  <?= $this->element('notify/alert', [
+    'message' => $message,
+    'type' => 'information',
+    'dismissible' => true
+  ]) ?>
 <?php endif; ?>
\ No newline at end of file
diff --git a/app/templates/element/flash/success.php b/app/templates/element/flash/success.php
index 6f0671bb0..17c7469d5 100644
--- a/app/templates/element/flash/success.php
+++ b/app/templates/element/flash/success.php
@@ -8,5 +8,9 @@
   <?php /* CFM-221: while a prefix such as "Error: " or "Success: " can be sent with the Alert, 
     we avoid prefixes to better support LTR languages. Prefixes, if desired, should be included 
     directly in the language strings instead. */ ?>
-  <?= $this->Alert->alert($message, 'success', true) ?>
+  <?= $this->element('notify/alert', [
+    'message' => $message,
+    'type' => 'success',
+    'dismissible' => true
+  ]) ?>
 <?php endif; ?>
\ No newline at end of file
diff --git a/app/templates/element/form/entityID.php b/app/templates/element/form/entityID.php
new file mode 100644
index 000000000..9f24868e0
--- /dev/null
+++ b/app/templates/element/form/entityID.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * COmanage Registry Unordered List Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+?>
+
+<?php if(isset($vv_obj?->id)): ?>
+<li id="cm-entity-id">
+  <?= __d('information', 'entity.id', $vv_obj->id) ?>
+</li>
+<?php endif; ?>
+
diff --git a/app/templates/element/form/fieldDiv.php b/app/templates/element/form/fieldDiv.php
new file mode 100644
index 000000000..2f383ca68
--- /dev/null
+++ b/app/templates/element/form/fieldDiv.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * COmanage Registry Field Div Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+?>
+
+<div class="field">
+  <?php
+  // Name Div
+  print $this->element('form/nameDiv');
+
+  // Info Div
+  if(isset($vv_field_arguments['fieldPrefix'])) {
+    print $this->element('form/infoDiv/withPrefix');
+  } elseif(isset($vv_field_arguments['status'])) {
+    print $this->element('form/infoDiv/status');
+  } elseif(isset($vv_field_arguments['groupedControls'])) {
+    print $this->element('form/infoDiv/grouped');
+  } elseif(isset($vv_field_arguments['entity'])) {
+    print $this->element('form/infoDiv/source');
+  } elseif(isset($vv_field_arguments['check']) && $vv_field_arguments['check']) {
+    print $this->element('form/infoDiv/check');
+  } elseif(isset($vv_field_arguments['groupmember'])) {
+    print $this->element('form/infoDiv/groupMember');
+  } elseif(isset($vv_field_arguments['autocomplete'])) {
+    print $this->element('form/infoDiv/autocomplete');
+  } else {
+    print $this->element('form/infoDiv/default');
+  }
+  ?>
+</div>
\ No newline at end of file
diff --git a/app/templates/element/form/infoDiv/autocomplete.php b/app/templates/element/form/infoDiv/autocomplete.php
new file mode 100644
index 000000000..787a54c1a
--- /dev/null
+++ b/app/templates/element/form/infoDiv/autocomplete.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * COmanage Registry Autocomplete Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+
+declare(strict_types = 1);
+
+// Create a field name for the autocomplete input
+$autoCompleteFieldName = 'cm_autocomplete_' . $fieldName;
+
+// Because we use JavaScript to set the value of the hidden field,
+// disable form-tamper checking for the autocomplete fields.
+// XXX We ought not have to do this for the hidden field ($fieldName) at least
+$this->Form->unlockField($fieldName);
+$this->Form->unlockField($autoCompleteFieldName);
+
+$autocompleteArgs = [
+  'type' => 'field',
+  'fieldName' => $fieldName,
+  'personType' => 'person',
+  'htmlId' => $autoCompleteFieldName,
+  'viewConfigParameters' => $vv_field_arguments['autocomplete']['configuration']
+];
+
+?>
+
+
+<?php
+  // Create a hidden field to hold our value and emit the autocomplete widget
+  print $this->Form->hidden($fieldName, $vv_field_arguments['fieldOptions']) . $this->element('peopleAutocomplete', $autocompleteArgs);
+?>
+<div class="field-desc">
+  <span class="material-icons">info</span>
+  <?= __d('operation','autocomplete.people.desc',['2']) ?>
+</div>
diff --git a/app/templates/element/form/infoDiv/check.php b/app/templates/element/form/infoDiv/check.php
new file mode 100644
index 000000000..237eeac66
--- /dev/null
+++ b/app/templates/element/form/infoDiv/check.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * COmanage Registry Form Check Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+?>
+
+<div class="field-info">
+  <div class="field-suppliment">
+    <div class="form-check">
+      <input class="form-check-input" type="checkbox" value="" id="format-toggle">
+      <label class="form-check-label" for="format-toggle"><?= __d('field','format') ?></label>
+    </div>
+  </div>
+  <?= $this->Field->formField(...$vv_field_arguments) ?>
+  <script>
+    parametersValue = $("#<?= $fieldName ?>").val();
+    parametersJSON = JSON.parse(parametersValue);
+    $("#format-toggle").click(function() {
+      if($(this).is(":checked")) {
+        $("#<?= $fieldName ?>").val(JSON.stringify(parametersJSON, null, 4));
+        paramsHeight = Object.keys(parametersJSON).length + 6 + "em";
+        $("#<?= $fieldName ?>").css("height",paramsHeight);
+      } else {
+        $("#<?= $fieldName ?>").val(parametersValue);
+        $("#<?= $fieldName ?>").css("height","4em");
+      }
+    });
+  </script>
+</div>
\ No newline at end of file
diff --git a/app/templates/element/form/infoDiv/default.php b/app/templates/element/form/infoDiv/default.php
new file mode 100644
index 000000000..fe1aa2e71
--- /dev/null
+++ b/app/templates/element/form/infoDiv/default.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * COmanage Registry Info Div Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+?>
+<div class="field-info">
+  <?= $this->Field->formField(...$vv_field_arguments) ?>
+</div>
\ No newline at end of file
diff --git a/app/templates/element/form/infoDiv/groupMember.php b/app/templates/element/form/infoDiv/groupMember.php
new file mode 100644
index 000000000..8d4b6069e
--- /dev/null
+++ b/app/templates/element/form/infoDiv/groupMember.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * COmanage Registry GroupMember Info Div Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+// vv_selected_person parameter is set by the controller.
+?>
+
+<?php if(isset($vv_selected_person)): ?>
+<span class="group-member-to-add-name">
+  <?= $vv_selected_person['name'] ?>
+</span>
+<span class="group-member-to-add-id">
+  (<?= __d('information', 'entity.id', [$vv_selected_person['id']]) ?>)
+</span>
+<?php endif; ?>
diff --git a/app/templates/element/form/infoDiv/grouped.php b/app/templates/element/form/infoDiv/grouped.php
new file mode 100644
index 000000000..c0a89aaf7
--- /dev/null
+++ b/app/templates/element/form/infoDiv/grouped.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * COmanage Registry Info Div Grouped Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+$classes = '';
+
+
+?>
+
+<div class="field-info">
+  <?php foreach ($vv_field_arguments['groupedControls'] as $fieldName => $fieldArguments): ?>
+    <?php
+    if(isset($fieldArguments['singleRowItem']) && $fieldArguments['singleRowItem']) {
+      $classes .= 'd-block ';
+      // This configuration is not needed for the control construction
+      unset($fieldArguments['singleRowItem']);
+    }
+    ?>
+  <div class="subfield subfield-cols <?= $classes ?>">
+    <div class="field-col">
+    <?= $this->Field->formField($fieldName, ...$fieldArguments) ?>
+    </div>
+  </div>
+  <?php endforeach; ?>
+</div>
\ No newline at end of file
diff --git a/app/templates/element/form/infoDiv/source.php b/app/templates/element/form/infoDiv/source.php
new file mode 100644
index 000000000..e9d222642
--- /dev/null
+++ b/app/templates/element/form/infoDiv/source.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * COmanage Registry Info Div Source Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+$entity = $vv_field_arguments['entity'];
+
+?>
+<div>
+  <?= $this->Field->sourceLink($entity) ?>
+</div>
diff --git a/app/templates/element/form/infoDiv/status.php b/app/templates/element/form/infoDiv/status.php
new file mode 100644
index 000000000..404c997c9
--- /dev/null
+++ b/app/templates/element/form/infoDiv/status.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * COmanage Registry Status Info Div Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+/*
+ * Parameters:
+ * string $status
+ * array  $link
+ */
+
+declare(strict_types = 1);
+
+$status = $vv_field_arguments['status'];
+$linkHtml = $status;
+$link = $vv_field_arguments['link'] ?? [];
+
+
+if($link) {
+  // Construct HTML for the requested link
+  if(!empty($link['label'])) {
+    // Create a separate link after $status
+
+    $linkHtml .= ' ' . $this->Html->link(
+        $link['label'],
+        $link['url'],
+        $link
+      );
+  } else {
+    // Make $status the link
+
+    $linkHtml = $this->Html->link(
+      $status,
+      $link['url'],
+      // Pass whatever other args are specified
+      $link
+    );
+  }
+}
+
+?>
+<div class="field-info">
+  <?= $linkHtml ?>
+</div>
\ No newline at end of file
diff --git a/app/templates/element/form/infoDiv/withPrefix.php b/app/templates/element/form/infoDiv/withPrefix.php
new file mode 100644
index 000000000..17c4189df
--- /dev/null
+++ b/app/templates/element/form/infoDiv/withPrefix.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * COmanage Registry Input Prefix Div Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+?>
+<div class="field-info">
+  <div class="input-group mb-3">
+    <div class="input-group-prepend">
+      <span class="input-group-text" id="basic-addon3"><?= $vv_field_arguments['fieldPrefix'] ?></span>
+    </div>
+    <?= $this->Field->formField(...$vv_field_arguments)?>
+  </div>
+</div>
diff --git a/app/templates/element/form/listItem.php b/app/templates/element/form/listItem.php
new file mode 100644
index 000000000..2774f259a
--- /dev/null
+++ b/app/templates/element/form/listItem.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * COmanage Registry Unordered List Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+// Make the element configuration available downstream
+// XXX Unfortunately CAKEPHP doe not create a viewvar space for the element
+//     parameters. As a result we do not know which one is which unles we:
+//     - add a prefix and create a namespace
+//     - wrap them in an array.
+//     We choose the latter.
+$this->set('fieldName', $arguments['fieldName']);
+$fieldName = $arguments['fieldName'];
+$this->set('vv_field_arguments', $arguments);
+
+// Class calculation by field Type
+$classes = match ($this->Field->getFieldType($fieldName)) {
+  'date',
+  'datetime',
+  'timestamp'     => 'fields-datepicker ',
+  default         => ''
+};
+
+// Class calculation by field name
+$classes .= match ($fieldName) {
+  'source_record' => 'source-record ',
+  'retry_interval',
+  'login'         => 'subfield ',
+  default         => ''
+};
+
+// Class calculation by type of Info Div
+if(isset($arguments['autocomplete'])) {
+  $classes .= 'fields-people-autocomplete ';
+}
+
+
+// If an attribute is frozen, inject a special link to unfreeze it, since
+// the attribute is read-only and the admin can't simply uncheck the setting
+if($fieldName == 'frozen' && $this->Field->getEntity()->frozen) {
+  $url = [
+    'label' => __d('operation', 'unfreeze'),
+    'url' => [
+      'plugin'      => null,
+      'controller'  => \App\Lib\Util\StringUtilities::entityToClassname($this->Field->getEntity()),
+      'action'      => 'unfreeze',
+      $this->Field->getEntity()->id
+    ]
+  ];
+  $arguments = [
+    ...$arguments,
+    'status' => __d('field', 'frozen'),
+    'link' => $url,
+  ];
+  $this->set('vv_field_arguments', $arguments);
+}
+
+// If an attribute is a plugin, return the link to its configuration
+if($fieldName == 'plugin' && $vv_action == 'edit') {
+  $url = [
+    'label' => __d('operation', 'configure.plugin'),
+    'url' => [
+      'plugin'      => null,
+      'controller'  => \App\Lib\Util\StringUtilities::entityToClassname($this->Field->getEntity()),
+      'action'      => 'configure',
+      $this->Field->getEntity()->id
+    ]
+  ];
+  $arguments = [
+    ...$arguments,
+    'status' => $this->Field->getEntity()->$fieldName,
+    'link' => $url,
+  ];
+  $this->set('vv_field_arguments', $arguments);
+}
+
+?>
+
+<li class="<?= trim($classes) ?>">
+  <?= $this->element('form/fieldDiv')?>
+</li>
diff --git a/app/templates/element/form/nameDiv.php b/app/templates/element/form/nameDiv.php
new file mode 100644
index 000000000..06ab77505
--- /dev/null
+++ b/app/templates/element/form/nameDiv.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * COmanage Registry Name Div Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+/*
+ * Parameters
+ * string $fieldName
+ * string $fieldLabel
+ * bool   $labelIsTextOnly
+ */
+
+declare(strict_types = 1);
+
+use Cake\Utility\Inflector;
+
+
+$classes = '';
+
+// We'll accept a fieldName of the form other_models.0.foo for forms that
+// request associated data. Note, however, that model names for language
+// keys are OtherModel, so we'll need to inflect.
+
+$mn = $this->Field->getModelName();
+$fn = $fieldName;
+
+if(str_contains($fieldName, '.')) {
+  // othermodels.0.field
+
+  $bits = explode('.', $fieldName, 3);
+  $mn = Inflector::classify($bits[0]);
+  $fn = $bits[2];
+}
+
+[$label, $desc] = $this->Field->calculateLabelAndDescription($fn);
+$label = $vv_field_arguments['fieldLabel'] ?? $label;
+
+// Override the default required behavior if the field has the required
+// option set
+$optionsRequired = isset($vv_field_arguments['fieldOptions']['required'])
+                   && $vv_field_arguments['fieldOptions']['required'];
+
+// Extra class required for the grouped controls elements
+if(isset($groupedControls)) {
+  $classes .= 'align-top ';
+}
+?>
+
+<div class="field-name <?= $classes ?>">
+  <div class="field-title">
+    <!-- Will this work for accessibility? -->
+    <?php if(
+             (isset($vv_field_arguments['labelIsTextOnly']) && !$vv_field_arguments['labelIsTextOnly'])
+             && $this->Field->getFieldType($fieldName) !== 'boolean'
+           ):
+      ?>
+      <?= $this->Form->label($fn, $label) ?>
+    <!-- We print the login checkbox along with the Identifier type. -->
+    <!-- As a result, the label is redundant -->
+    <?php elseif($fieldName != 'login'): ?>
+      <?= $label ?>
+    <?php endif; ?>
+    <?php
+
+    /*
+     * Required Span
+     */
+    if($this->Field->isEditable()
+       &&
+       ($this->Field->isReqField($fn) || $optionsRequired)
+    ) {
+      print $this->element('form/requiredSpan', [], [
+        'cache' => '_html_elements',
+      ]);
+    }
+    ?>
+    </div>
+  <?php if(isset($desc)): ?>
+  <div class="field-desc">
+    <?= $desc ?>
+  </div>
+  <?php endif; // description?>
+</div>
\ No newline at end of file
diff --git a/app/templates/element/form/notSetDiv.php b/app/templates/element/form/notSetDiv.php
new file mode 100644
index 000000000..c156d03fb
--- /dev/null
+++ b/app/templates/element/form/notSetDiv.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * COmanage Registry Not Set Div Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+?>
+
+<div class="not-set"><?= __d('information', 'notset') ?></div>
\ No newline at end of file
diff --git a/app/templates/element/form/requiredSpan.php b/app/templates/element/form/requiredSpan.php
new file mode 100644
index 000000000..20e2a2a50
--- /dev/null
+++ b/app/templates/element/form/requiredSpan.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * COmanage Registry Required Span Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+?>
+
+<span class='required' aria-hidden='true'>*</span>
+<span class='visually-hidden'><?= __d('field', 'required') ?></span>
\ No newline at end of file
diff --git a/app/templates/element/form/submit.php b/app/templates/element/form/submit.php
new file mode 100644
index 000000000..2063db9f4
--- /dev/null
+++ b/app/templates/element/form/submit.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * COmanage Registry Submit Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+?>
+
+<?php if($this->Field->isEditable()): ?>
+  <li class="fields-submit">
+    <div class="field">
+      <div class="field-name">
+        <span class="required">* <?= __d('field', 'required') ?></span>
+      </div>
+      <div class="field-info">
+        <?= $this->Form->submit($label) ?>
+      </div>
+    </div>
+  </li>
+<?php endif; ?>
\ No newline at end of file
diff --git a/app/templates/element/form/unorderedList.php b/app/templates/element/form/unorderedList.php
new file mode 100644
index 000000000..4d3f8a9aa
--- /dev/null
+++ b/app/templates/element/form/unorderedList.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * COmanage Registry Unordered List Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+// View vars
+// $vv_obj
+// $vv_required_fields
+// $vv_action
+// $vv_fields_inc
+// $vv_template_path
+// $vv_field_types
+
+?>
+<ul id="<?= $vv_action . '_' . $this->name ?>" class="fields form-list">
+  <?php
+  // We allow the fields.inc file to be specified for Controllers that have more
+  // complicated/non-default actions.
+  // XXX Each fields.inc file will calculate and provide the hidden controls.
+  $fieldsFile = $vv_fields_inc ?? 'fields.inc';
+  // The controller will calculate the template path for us, since it could be
+  // in one of several paths if we are in a plugin context.
+  // The include files will contain the listItem elements
+  include($vv_template_path . DS . $fieldsFile);
+  // Element ID
+  print $this->element('form/entityID');
+  // The Submit element will be printed only if we are adding or updating
+  print $this->element('form/submit', ['label' => __d('operation', 'save')]);
+  ?>
+</ul>
+
+<?php
+// Import all the hidden fields in the Form
+if(!empty($hidden)) {
+// Inject any hidden variables set by the included file
+  foreach($hidden as $attr => $v) {
+    print $this->Form->hidden($attr, ['value' => $v]);
+  }
+}
\ No newline at end of file
diff --git a/app/templates/element/menuPanel.php b/app/templates/element/menuPanel.php
index d4065b255..8790380c3 100644
--- a/app/templates/element/menuPanel.php
+++ b/app/templates/element/menuPanel.php
@@ -485,7 +485,11 @@
       ];
       ?>
       <div class="config-platform-notice">
-        <?= $this->Alert->alert(__d('information','cmp.config.notice', $noticeUrls), 'information', true) ?>
+        <?= $this->element('notify/alert', [
+          'message' => __d('information','cmp.config.notice', $noticeUrls),
+          'type' => 'information',
+          'dismissible' => true
+          ]) ?>
       </div>
     <?php endif; ?>
     <div class="comanage-version">
diff --git a/app/templates/element/mveaJs.php b/app/templates/element/mveaJs.php
index 3ae2e54b5..7360b44e1 100644
--- a/app/templates/element/mveaJs.php
+++ b/app/templates/element/mveaJs.php
@@ -67,7 +67,8 @@
           action:  '<?= $vv_action ?>'
         },
         txt: JSON.parse('<?= json_encode($vueHelper->locales()) ?>'),
-        isLoading: true
+        isLoading: true,
+        title: '<?= $title?>'
       }
     },
     components: {
@@ -113,32 +114,33 @@
     },
     created() {
       this.refreshComponent();
-    }
+    },
+    template:
+    `<div class="card h-100">
+        <div class="card-body">
+          <h2 class="card-title">
+            {{ title }}
+            <span v-show="isLoading" class="co-loading-mini" role="status">
+              <span></span><span></span><span></span>
+            </span>
+          </h2>
+          <div class="card-text">
+            <ul v-show="isLoading" class="cm-mvea fields data-list skeleton-list">
+              <li><span class="visually-hidden">Loading...</span></li>
+            </ul>
+            <mveas
+              :mveas="this.mveas"
+              :core="this.core"
+              :txt="this.txt">
+            </mveas>
+          </div>
+        </div>
+      </div>
+    `
   });
 
   // Mount the component and provide a global reference for this app instance.
   window.mvea<?= $mveaType ?> = app.mount("#<?= $htmlId ?>");
 </script>
 
-<div id="<?= $htmlId ?>" class="col cm-mvea-col">
-  <div class="card h-100">
-    <div class="card-body">
-      <h2 class="card-title">
-        <?= $title ?>
-        <span v-show="isLoading" class="co-loading-mini" role="status">
-          <span></span><span></span><span></span>
-        </span>
-      </h2>
-      <div class="card-text">
-        <ul v-show="isLoading" class="cm-mvea fields data-list skeleton-list">
-          <li><span class="visually-hidden">Loading...</span></li>
-        </ul>
-        <mveas
-          :mveas="this.mveas"
-          :core="this.core"
-          :txt="this.txt">
-        </mveas>
-      </div>
-    </div>
-  </div>
-</div>
+<div id="<?= $htmlId ?>" class="col cm-mvea-col"></div>
diff --git a/app/templates/element/notify/alert.php b/app/templates/element/notify/alert.php
new file mode 100644
index 000000000..8e3359087
--- /dev/null
+++ b/app/templates/element/notify/alert.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * COmanage Registry Banner List Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+/*
+ * Parameters:
+ * $type          : String,  required
+ * $message       : String,  required
+ * $dismissible   : Boolean, optional
+ */
+
+$type ??= 'warning';
+
+$alertClass = "alert-{$type}";
+$showButton = false;
+
+if(isset($dismissible) && $dismissible) {
+  $alertClass .= ' alert-dismissible';
+  $showButton = true;
+}
+?>
+
+<div class="alert <?= $alertClass ?> co-alert" role="alert">
+  <div class="alert-body d-flex align-items-center">
+    <span class="alert-title d-flex align-items-center">
+      <span class="material-icons-outlined alert-icon"><?= $this->Alert->getAlertIcon($type) ?></span>
+      <?php if(isset($title)): ?>
+      <span class="alert-title-text"><?= $title ?></span>
+      <?php endif; ?>
+    </span>
+    <span class="alert-message">
+      <?= $message ?>
+    </span>
+    <?php
+      if($showButton) {
+        print $this->element('notify/closeButton');
+      }
+    ?>
+  </div>
+</div>
diff --git a/app/templates/element/notify/banner.php b/app/templates/element/notify/banner.php
new file mode 100644
index 000000000..927e7fc0f
--- /dev/null
+++ b/app/templates/element/notify/banner.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * COmanage Registry Banner List Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+// Parameters:
+// $info: String, required
+
+?>
+
+
+<li class="alert-banner">
+  <?= $this->element('notify/alert', ['message' => $info]) ?>
+</li>
diff --git a/app/templates/element/notify/closeButton.php b/app/templates/element/notify/closeButton.php
new file mode 100644
index 000000000..b7f5efa99
--- /dev/null
+++ b/app/templates/element/notify/closeButton.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * COmanage Registry Close Button Element
+ *
+ * Portions licensed to the University Corporation for Advanced Internet
+ * Development, Inc. ("UCAID") under one or more contributor license agreements.
+ * See the NOTICE file distributed with this work for additional information
+ * regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @link          https://www.internet2.edu/comanage COmanage Project
+ * @package       registry
+ * @since         COmanage Registry v5.0.0
+ * @license       Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
+ */
+
+
+declare(strict_types = 1);
+
+?>
+
+<span class="alert-button">
+   <button type="button" class="btn-close nospin" data-bs-dismiss="alert" aria-label="Close"></button>
+</span>
\ No newline at end of file
diff --git a/app/templates/element/peopleAutocomplete.php b/app/templates/element/peopleAutocomplete.php
index a1d8efc22..bf7fbe1f4 100644
--- a/app/templates/element/peopleAutocomplete.php
+++ b/app/templates/element/peopleAutocomplete.php
@@ -104,7 +104,15 @@
         console.error(res);
         console.log('Status Code: ', res.status)
       }
-    }
+    },
+    template: `
+        <autocomplete-people
+          :options="this.autocompleteOptions"
+          :core="this.core"
+          appendTo='self'
+          :txt="this.txt">
+        </autocomplete-people>
+    `
   });
 
 
@@ -118,10 +126,4 @@
   window.<?= $htmlId ?> = app.mount("#<?= $htmlId ?>-container");
 </script>
 
-<div id="<?= $htmlId ?>-container" class="cm-autocomplete-container">
-  <autocomplete-people
-    :options="this.autocompleteOptions"
-    :core="this.core"
-    :txt="this.txt">
-  </autocomplete-people>
-</div>
+<div id="<?= $htmlId ?>-container" class="cm-autocomplete-container"></div>
diff --git a/app/templates/layout/default.php b/app/templates/layout/default.php
index 0138389d1..54212e4c1 100644
--- a/app/templates/layout/default.php
+++ b/app/templates/layout/default.php
@@ -64,13 +64,13 @@
     ]) . PHP_EOL ?>
 
     <!-- Load Bootstrap, jQuery, and Vue (other scripts at bottom) -->
-    <!-- Refer to the following link for any extra libraries https://cdnjs.com/libraries/primevue/3.48.1 -->
+    <!-- https://unpkg.com/browse/primevue@3.51.0  -->
     <?= $this->Html->script([
       'bootstrap/bootstrap.bundle.min.js',
       'jquery/jquery.min.js',
       'vue/vue-3.2.31.global.prod.js',
-      'vue/primevue-3.48.1.core.min.js',
-      'vue/primevue-3.48.1.autocomplete.min.js'
+      'vue/primevue-3.51.0.core.min.js',
+      'vue/primevue-3.51.0.autocomplete.min.js'
     ]) . PHP_EOL ?>
 
     <!-- Include external files and scripts -->
diff --git a/app/templates/layout/iframe.php b/app/templates/layout/iframe.php
index cffdcf1a4..725e645e1 100644
--- a/app/templates/layout/iframe.php
+++ b/app/templates/layout/iframe.php
@@ -69,8 +69,8 @@
       'bootstrap/bootstrap.bundle.min.js',
       'jquery/jquery.min.js',
       'vue/vue-3.2.31.global.prod.js',
-      'vue/primevue-3.48.1.core.min.js',
-      'vue/primevue-3.48.1.autocomplete.min.js'
+      'vue/primevue-3.51.0.core.min.js',
+      'vue/primevue-3.51.0.autocomplete.min.js'
     ]) . PHP_EOL ?>
 
     <!-- Include external files and scripts -->
diff --git a/app/webroot/js/comanage/comanage.js b/app/webroot/js/comanage/comanage.js
index f0d8b71fa..2d599837c 100644
--- a/app/webroot/js/comanage/comanage.js
+++ b/app/webroot/js/comanage/comanage.js
@@ -64,7 +64,7 @@ function showFields(fields, isPageLoad) {
       $('#' + field).closest('li').addClass('collapse show');
     } else {
       $('#' + field).closest('li').collapse('show');
-    }  
+    }
   }
 }