diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/element_units_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/element_units_service.py
index 81340e79..ecebda69 100644
--- a/spiffworkflow-backend/src/spiffworkflow_backend/services/element_units_service.py
+++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/element_units_service.py
@@ -58,7 +58,7 @@ class ElementUnitsService:
                 # make mypy happy
                 return None
 
-            current_app.logger.info(f"Checking element unit cache @ {cache_key} :: '{process_id}' - '{element_id}'")
+            current_app.logger.debug(f"Checking element unit cache @ {cache_key} :: '{process_id}' - '{element_id}'")
 
             bpmn_spec_json = spiff_element_units.workflow_from_cached_element_unit(
                 cache_dir, cache_key, process_id, element_id
diff --git a/spiffworkflow-frontend/src/components/InstructionsForEndUser.tsx b/spiffworkflow-frontend/src/components/InstructionsForEndUser.tsx
index b0484bec..644a7cc8 100644
--- a/spiffworkflow-frontend/src/components/InstructionsForEndUser.tsx
+++ b/spiffworkflow-frontend/src/components/InstructionsForEndUser.tsx
@@ -1,8 +1,8 @@
 import React, { useEffect, useState } from 'react';
 // @ts-ignore
-import MDEditor from '@uiw/react-md-editor';
 import { Toggle } from '@carbon/react';
 import FormattingService from '../services/FormattingService';
+import MarkdownRenderer from './MarkdownRenderer';
 
 type OwnProps = {
   task: any;
@@ -87,9 +87,8 @@ export default function InstructionsForEndUser({
           https://www.npmjs.com/package/@uiw/react-md-editor switches to dark mode by default by respecting @media (prefers-color-scheme: dark)
           This makes it look like our site is broken, so until the rest of the site supports dark mode, turn off dark mode for this component.
         */}
-        <div data-color-mode="light">
-          <MDEditor.Markdown linkTarget="_blank" source={instructions} />
-        </div>
+
+        <MarkdownRenderer linkTarget="_blank" source={instructions} />
       </div>
       {showCollapseToggle()}
     </div>
diff --git a/spiffworkflow-frontend/src/components/MarkdownDisplayForFile.tsx b/spiffworkflow-frontend/src/components/MarkdownDisplayForFile.tsx
index 15be7204..0be0f259 100644
--- a/spiffworkflow-frontend/src/components/MarkdownDisplayForFile.tsx
+++ b/spiffworkflow-frontend/src/components/MarkdownDisplayForFile.tsx
@@ -1,6 +1,6 @@
-import MDEditor from '@uiw/react-md-editor';
 import { useEffect, useState } from 'react';
 import HttpService from '../services/HttpService';
+import MarkdownRenderer from './MarkdownRenderer';
 
 type OwnProps = {
   apiPath: string;
@@ -24,9 +24,11 @@ export default function MarkdownDisplayForFile({ apiPath }: OwnProps) {
 
   if (markdownContents) {
     return (
-      <div data-color-mode="light" className="with-bottom-margin">
-        <MDEditor.Markdown linkTarget="_blank" source={markdownContents} />
-      </div>
+      <MarkdownRenderer
+        linkTarget="_blank"
+        source={markdownContents}
+        wrapperClassName="with-bottom-margin"
+      />
     );
   }
 
diff --git a/spiffworkflow-frontend/src/components/MarkdownRenderer.tsx b/spiffworkflow-frontend/src/components/MarkdownRenderer.tsx
new file mode 100644
index 00000000..f4d52ad2
--- /dev/null
+++ b/spiffworkflow-frontend/src/components/MarkdownRenderer.tsx
@@ -0,0 +1,16 @@
+import MDEditor from '@uiw/react-md-editor';
+
+export default function MarkdownRenderer(props: any) {
+  let wrapperClassName = '';
+  const propsToUse = props;
+  if ('wrapperClassName' in propsToUse) {
+    wrapperClassName = propsToUse.wrapperClassName;
+    delete propsToUse.wrapperClassName;
+  }
+  return (
+    <div data-color-mode="light" className={wrapperClassName}>
+      {/* eslint-disable-next-line react/jsx-props-no-spreading */}
+      <MDEditor.Markdown {...propsToUse} />
+    </div>
+  );
+}
diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx
index 95e6a517..c8c53cf2 100644
--- a/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx
+++ b/spiffworkflow-frontend/src/components/ProcessInstanceRun.tsx
@@ -66,20 +66,21 @@ const storeRecentProcessModelInLocalStorage = (
 
 type OwnProps = {
   processModel: ProcessModel;
-  onSuccessCallback: Function;
   className?: string;
   checkPermissions?: boolean;
+  buttonText?: string;
 };
 
 export default function ProcessInstanceRun({
   processModel,
-  onSuccessCallback,
   className,
   checkPermissions = true,
+  buttonText = 'Start',
 }: OwnProps) {
   const navigate = useNavigate();
   const { addError, removeError } = useAPIError();
   const [disableStartButton, setDisableStartButton] = useState<boolean>(false);
+
   const modifiedProcessModelId = modifyProcessIdentifierForPathParam(
     processModel.id
   );
@@ -98,16 +99,15 @@ export default function ProcessInstanceRun({
   const onProcessInstanceRun = (processInstance: any) => {
     const processInstanceId = (processInstance as any).id;
     navigate(
-      `/process-instances/for-me/${modifyProcessIdentifierForPathParam(
-        processModel.id
-      )}/${processInstanceId}/interstitial`
+      `/process-instances/for-me/${modifiedProcessModelId}/${processInstanceId}/interstitial`
     );
-    onSuccessCallback(processInstance);
   };
 
   const processModelRun = (processInstance: any) => {
     removeError();
-    storeRecentProcessModelInLocalStorage(processModel);
+    if (processModel) {
+      storeRecentProcessModelInLocalStorage(processModel);
+    }
     HttpService.makeCallToBackend({
       path: `/process-instances/${modifiedProcessModelId}/${processInstance.id}/run`,
       successCallback: onProcessInstanceRun,
@@ -141,7 +141,7 @@ export default function ProcessInstanceRun({
       disabled={disableStartButton}
       size="md"
     >
-      Start
+      {buttonText}
     </Button>
   );
 
diff --git a/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx b/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx
index d92c992b..5c55b5ec 100644
--- a/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx
+++ b/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx
@@ -1,17 +1,16 @@
 import { ReactElement, useEffect, useState } from 'react';
-import { Link, useSearchParams } from 'react-router-dom';
+import { useSearchParams } from 'react-router-dom';
 import {
   Tile,
   // @ts-ignore
 } from '@carbon/react';
 import HttpService from '../services/HttpService';
-import { ProcessModel, ProcessInstance, ProcessGroup } from '../interfaces';
+import { ProcessModel, ProcessGroup } from '../interfaces';
 import {
   modifyProcessIdentifierForPathParam,
   truncateString,
 } from '../helpers';
 import ProcessInstanceRun from './ProcessInstanceRun';
-import { Notification } from './Notification';
 
 type OwnProps = {
   headerElement?: ReactElement;
@@ -28,8 +27,6 @@ export default function ProcessModelListTiles({
   const [processModels, setProcessModels] = useState<ProcessModel[] | null>(
     null
   );
-  const [processInstance, setProcessInstance] =
-    useState<ProcessInstance | null>(null);
 
   useEffect(() => {
     const setProcessModelsFromResult = (result: any) => {
@@ -48,27 +45,6 @@ export default function ProcessModelListTiles({
     });
   }, [searchParams, processGroup]);
 
-  const processInstanceRunResultTag = () => {
-    if (processInstance) {
-      return (
-        <Notification
-          title={`Process Instance ${processInstance.id} kicked off`}
-          onClose={() => setProcessInstance(null)}
-        >
-          <Link
-            to={`/process-instances/${modifyProcessIdentifierForPathParam(
-              processInstance.process_model_identifier
-            )}/${processInstance.id}`}
-            data-qa="process-instance-show-link"
-          >
-            view
-          </Link>
-        </Notification>
-      );
-    }
-    return null;
-  };
-
   const processModelsDisplayArea = () => {
     let displayText = null;
     if (processModels && processModels.length > 0) {
@@ -95,7 +71,6 @@ export default function ProcessModelListTiles({
               </p>
               <ProcessInstanceRun
                 processModel={row}
-                onSuccessCallback={setProcessInstance}
                 className="tile-pin-bottom"
                 checkPermissions={checkPermissions}
               />
@@ -114,7 +89,6 @@ export default function ProcessModelListTiles({
       return (
         <>
           {headerElement}
-          {processInstanceRunResultTag()}
           {processModelsDisplayArea()}
         </>
       );
diff --git a/spiffworkflow-frontend/src/extension_ui_schema_interfaces.ts b/spiffworkflow-frontend/src/extension_ui_schema_interfaces.ts
index 980e79d4..cb6959b6 100644
--- a/spiffworkflow-frontend/src/extension_ui_schema_interfaces.ts
+++ b/spiffworkflow-frontend/src/extension_ui_schema_interfaces.ts
@@ -37,10 +37,16 @@ export interface UiSchemaAction {
   full_api_path?: boolean;
 }
 
+export interface UiSchemaPageComponent {
+  name: string;
+  arguments: object;
+}
+
 export interface UiSchemaPageDefinition {
   header: string;
   api: string;
 
+  components?: UiSchemaPageComponent[];
   form?: UiSchemaForm;
   markdown_instruction_filename?: string;
   navigate_instead_of_post_to_api?: boolean;
diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts
index dbd3eb07..311d6eb8 100644
--- a/spiffworkflow-frontend/src/interfaces.ts
+++ b/spiffworkflow-frontend/src/interfaces.ts
@@ -146,6 +146,9 @@ export interface ProcessReference {
 }
 
 export type ObjectWithStringKeysAndValues = { [key: string]: string };
+export type ObjectWithStringKeysAndFunctionValues = {
+  [key: string]: Function;
+};
 
 export interface FilterOperator {
   id: string;
diff --git a/spiffworkflow-frontend/src/routes/Extension.tsx b/spiffworkflow-frontend/src/routes/Extension.tsx
index 7b302418..aa83f09c 100644
--- a/spiffworkflow-frontend/src/routes/Extension.tsx
+++ b/spiffworkflow-frontend/src/routes/Extension.tsx
@@ -1,10 +1,13 @@
 import { useCallback, useEffect, useState } from 'react';
 import { Button } from '@carbon/react';
-import MDEditor from '@uiw/react-md-editor';
 import { useParams, useSearchParams } from 'react-router-dom';
 import { Editor } from '@monaco-editor/react';
 import { useUriListForPermissions } from '../hooks/UriListForPermissions';
-import { ProcessFile, ProcessModel } from '../interfaces';
+import {
+  ObjectWithStringKeysAndFunctionValues,
+  ProcessFile,
+  ProcessModel,
+} from '../interfaces';
 import HttpService from '../services/HttpService';
 import useAPIError from '../hooks/UseApiError';
 import { recursivelyChangeNullAndUndefined } from '../helpers';
@@ -13,10 +16,13 @@ import { BACKEND_BASE_URL } from '../config';
 import {
   ExtensionPostBody,
   ExtensionUiSchema,
+  UiSchemaPageComponent,
   UiSchemaPageDefinition,
 } from '../extension_ui_schema_interfaces';
 import ErrorDisplay from '../components/ErrorDisplay';
 import FormattingService from '../services/FormattingService';
+import ProcessInstanceRun from '../components/ProcessInstanceRun';
+import MarkdownRenderer from '../components/MarkdownRenderer';
 
 type OwnProps = {
   displayErrors?: boolean;
@@ -43,9 +49,16 @@ export default function Extension({ displayErrors = true }: OwnProps) {
   }>({});
   const [uiSchemaPageDefinition, setUiSchemaPageDefinition] =
     useState<UiSchemaPageDefinition | null>(null);
+  const [readyForComponentsToDisplay, setReadyForComponentsToDisplay] =
+    useState<boolean>(false);
 
   const { addError, removeError } = useAPIError();
 
+  const supportedComponents: ObjectWithStringKeysAndFunctionValues = {
+    ProcessInstanceRun,
+    MarkdownRenderer,
+  };
+
   const setConfigsIfDesiredSchemaFile = useCallback(
     // eslint-disable-next-line sonarjs/cognitive-complexity
     (extensionUiSchemaFile: ProcessFile | null, pm: ProcessModel) => {
@@ -57,6 +70,7 @@ export default function Extension({ displayErrors = true }: OwnProps) {
           );
           setMarkdownToRenderOnLoad(newMarkdown);
         }
+        setReadyForComponentsToDisplay(true);
       };
 
       if (
@@ -98,6 +112,8 @@ export default function Extension({ displayErrors = true }: OwnProps) {
               httpMethod: 'POST',
               postBody,
             });
+          } else {
+            setReadyForComponentsToDisplay(true);
           }
         }
       }
@@ -238,7 +254,7 @@ export default function Extension({ displayErrors = true }: OwnProps) {
     }
   };
 
-  if (uiSchemaPageDefinition) {
+  if (readyForComponentsToDisplay && uiSchemaPageDefinition) {
     const componentsToDisplay = [<h1>{uiSchemaPageDefinition.header}</h1>];
     const markdownContentsToRender = [];
 
@@ -261,12 +277,28 @@ export default function Extension({ displayErrors = true }: OwnProps) {
 
     if (markdownContentsToRender.length > 0) {
       componentsToDisplay.push(
-        <div data-color-mode="light" className="with-bottom-margin">
-          <MDEditor.Markdown
-            linkTarget={mdEditorLinkTarget}
-            source={markdownContentsToRender.join('\n')}
-          />
-        </div>
+        <MarkdownRenderer
+          linkTarget={mdEditorLinkTarget}
+          source={markdownContentsToRender.join('\n')}
+          wrapperClassName="with-bottom-margin"
+        />
+      );
+    }
+
+    if (uiSchemaPageDefinition.components) {
+      uiSchemaPageDefinition.components.forEach(
+        (component: UiSchemaPageComponent) => {
+          if (supportedComponents[component.name]) {
+            const argumentsForComponent: any = component.arguments;
+            componentsToDisplay.push(
+              supportedComponents[component.name](argumentsForComponent)
+            );
+          } else {
+            console.error(
+              `Extension tried to use component with name '${component.name}' but that is not allowed.`
+            );
+          }
+        }
       );
     }
 
@@ -304,13 +336,12 @@ export default function Extension({ displayErrors = true }: OwnProps) {
     if (processedTaskData) {
       if (markdownToRenderOnSubmit) {
         componentsToDisplay.push(
-          <div data-color-mode="light" className="with-top-margin">
-            <MDEditor.Markdown
-              className="onboarding"
-              linkTarget="_blank"
-              source={markdownToRenderOnSubmit}
-            />
-          </div>
+          <MarkdownRenderer
+            className="onboarding"
+            linkTarget="_blank"
+            source={markdownToRenderOnSubmit}
+            wrapperClassName="with-top-margin"
+          />
         );
       } else {
         componentsToDisplay.push(
diff --git a/spiffworkflow-frontend/src/routes/MyTasks.tsx b/spiffworkflow-frontend/src/routes/MyTasks.tsx
index 6c4c925d..a62eb1b7 100644
--- a/spiffworkflow-frontend/src/routes/MyTasks.tsx
+++ b/spiffworkflow-frontend/src/routes/MyTasks.tsx
@@ -2,7 +2,6 @@ import { useEffect, useState } from 'react';
 // @ts-ignore
 import { Button, Table } from '@carbon/react';
 import { Link, useSearchParams } from 'react-router-dom';
-import { Notification } from '../components/Notification';
 import PaginationForTable from '../components/PaginationForTable';
 import {
   getPageInfoFromSearchParams,
@@ -12,7 +11,6 @@ import {
 import HttpService from '../services/HttpService';
 import {
   PaginationObject,
-  ProcessInstance,
   ProcessModel,
   RecentProcessModel,
 } from '../interfaces';
@@ -25,8 +23,6 @@ export default function MyTasks() {
   const [searchParams] = useSearchParams();
   const [tasks, setTasks] = useState([]);
   const [pagination, setPagination] = useState<PaginationObject | null>(null);
-  const [processInstance, setProcessInstance] =
-    useState<ProcessInstance | null>(null);
 
   useEffect(() => {
     const getTasks = () => {
@@ -52,27 +48,6 @@ export default function MyTasks() {
     );
   }, [searchParams]);
 
-  const processInstanceRunResultTag = () => {
-    if (processInstance) {
-      return (
-        <Notification
-          title={`Process Instance ${processInstance.id} kicked off`}
-          onClose={() => setProcessInstance(null)}
-        >
-          <Link
-            to={`/process-instances/${modifyProcessIdentifierForPathParam(
-              processInstance.process_model_identifier
-            )}/${processInstance.id}`}
-            data-qa="process-instance-show-link"
-          >
-            view
-          </Link>
-        </Notification>
-      );
-    }
-    return null;
-  };
-
   let recentProcessModels: RecentProcessModel[] = [];
   const recentProcessModelsString = localStorage.getItem('recentProcessModels');
   if (recentProcessModelsString !== null) {
@@ -163,10 +138,7 @@ export default function MyTasks() {
             </Link>
           </td>
           <td className="actions-cell">
-            <ProcessInstanceRun
-              processModel={processModel}
-              onSuccessCallback={setProcessInstance}
-            />
+            <ProcessInstanceRun processModel={processModel} />
           </td>
         </tr>
       );
@@ -220,7 +192,6 @@ export default function MyTasks() {
     }
     return (
       <>
-        {processInstanceRunResultTag()}
         {tasksWaitingForMe}
         <br />
         {relevantProcessModelSection}
diff --git a/spiffworkflow-frontend/src/routes/OnboardingView.tsx b/spiffworkflow-frontend/src/routes/OnboardingView.tsx
index 5903b26c..84c2334a 100644
--- a/spiffworkflow-frontend/src/routes/OnboardingView.tsx
+++ b/spiffworkflow-frontend/src/routes/OnboardingView.tsx
@@ -1,9 +1,9 @@
 import React, { useEffect, useState } from 'react';
-import MDEditor from '@uiw/react-md-editor';
 import { useLocation, useNavigate } from 'react-router-dom';
 import HttpService from '../services/HttpService';
 import { Onboarding } from '../interfaces';
 import { objectIsEmpty } from '../helpers';
+import MarkdownRenderer from '../components/MarkdownRenderer';
 
 export default function OnboardingView() {
   const [onboarding, setOnboarding] = useState<Onboarding | null>(null);
@@ -40,13 +40,11 @@ export default function OnboardingView() {
       onboarding.instructions.length > 0
     ) {
       return (
-        <div data-color-mode="light">
-          <MDEditor.Markdown
-            className="onboarding"
-            linkTarget="_blank"
-            source={onboarding.instructions}
-          />
-        </div>
+        <MarkdownRenderer
+          className="onboarding"
+          linkTarget="_blank"
+          source={onboarding.instructions}
+        />
       );
     }
     return null;
diff --git a/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx b/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx
index bb89c251..af00ad00 100644
--- a/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx
+++ b/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx
@@ -38,12 +38,7 @@ import {
   modifyProcessIdentifierForPathParam,
   setPageTitle,
 } from '../helpers';
-import {
-  PermissionsToCheck,
-  ProcessFile,
-  ProcessInstance,
-  ProcessModel,
-} from '../interfaces';
+import { PermissionsToCheck, ProcessFile, ProcessModel } from '../interfaces';
 import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
 import ProcessInstanceListTable from '../components/ProcessInstanceListTable';
 import { usePermissionFetcher } from '../hooks/PermissionService';
@@ -59,8 +54,6 @@ export default function ProcessModelShow() {
   const navigate = useNavigate();
 
   const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
-  const [processInstance, setProcessInstance] =
-    useState<ProcessInstance | null>(null);
   const [reloadModel, setReloadModel] = useState<boolean>(false);
   const [filesToUpload, setFilesToUpload] = useState<any>(null);
   const [showFileUploadModal, setShowFileUploadModal] =
@@ -120,25 +113,6 @@ export default function ProcessModelShow() {
     });
   }, [reloadModel, modifiedProcessModelId]);
 
-  const processInstanceRunResultTag = () => {
-    if (processInstance) {
-      return (
-        <Notification
-          title="Process Instance Kicked Off:"
-          onClose={() => setProcessInstance(null)}
-        >
-          <Link
-            to={`/process-instances/for-me/${modifiedProcessModelId}/${processInstance.id}`}
-            data-qa="process-instance-show-link"
-          >
-            view
-          </Link>
-        </Notification>
-      );
-    }
-    return null;
-  };
-
   const onUploadedCallback = () => {
     setReloadModel(true);
   };
@@ -729,10 +703,7 @@ export default function ProcessModelShow() {
           ability={ability}
         >
           <>
-            <ProcessInstanceRun
-              processModel={processModel}
-              onSuccessCallback={setProcessInstance}
-            />
+            <ProcessInstanceRun processModel={processModel} />
             <br />
             <br />
           </>
@@ -753,7 +724,6 @@ export default function ProcessModelShow() {
           ]}
         />
         {processModelPublishMessage()}
-        {processInstanceRunResultTag()}
         <Stack orientation="horizontal" gap={1}>
           <h1 className="with-icons">
             Process Model: {processModel.display_name}
diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx
index b5abcdff..82ebac66 100644
--- a/spiffworkflow-frontend/src/routes/TaskShow.tsx
+++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx
@@ -4,7 +4,6 @@ import { useNavigate, useParams } from 'react-router-dom';
 import { Grid, Column, Button, ButtonSet, Loading } from '@carbon/react';
 
 import { useDebouncedCallback } from 'use-debounce';
-import MDEditor from '@uiw/react-md-editor';
 import HttpService from '../services/HttpService';
 import useAPIError from '../hooks/UseApiError';
 import {
@@ -23,6 +22,7 @@ import CustomForm from '../components/CustomForm';
 import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
 import InstructionsForEndUser from '../components/InstructionsForEndUser';
 import UserService from '../services/UserService';
+import MarkdownRenderer from '../components/MarkdownRenderer';
 
 export default function TaskShow() {
   // get a basic task which doesn't get the form data so we can load
@@ -397,9 +397,7 @@ export default function TaskShow() {
 
   if (guestConfirmationText) {
     pageElements.push(
-      <div data-color-mode="light">
-        <MDEditor.Markdown linkTarget="_blank" source={guestConfirmationText} />
-      </div>
+      <MarkdownRenderer linkTarget="_blank" source={guestConfirmationText} />
     );
   } else if (basicTask && taskData) {
     pageElements.push(<InstructionsForEndUser task={taskWithTaskData} />);