      {:expanded false})
    :render
    (fn [{:keys [props state]}]
-     [:div {}
-      (create-field
-       (:label props)
-       (if (empty? (:data props))
-         "None"
-         (links/create-internal {:onClick #(swap! state update :expanded not)}
-           (if (:expanded @state) "Hide" "Show"))))
-      (when (:expanded @state)
-        [:div {:style {:padding "0.25em 0 0.25em 1em"}}
-         (let [namespace (get-in props [:workspace-id :namespace])
-               columns [{:header "Label"
-                         :column-data #(last (string/split (key %) #"\."))}
-                        {:header "Value"
-                         :initial-width :auto
-                         :sortable? false
-                         :column-data #(display-value namespace (second %))}]
-               task-column {:header "Task"
-                            :column-data #(second (string/split (key %) #"\."))}]
-           [Table
-            {:data (:data props)
-             :body {:style table-style/table-heavy
-                    :behavior {:reorderable-columns? false
-                               :filterable? false}
-                    :columns (if (:call-detail? props) columns (cons task-column columns))}}])])])})
+     (let [{:keys [data-fn data-path data workspace-id]} props]
+       [:div {}
+        (create-field
+         (:label props)
+           ;; when the user clicks to expand, trigger the request to get data
+           (links/create-internal {:onClick #(when (:expanded (swap! state update :expanded not)) (data-fn))}
+             (if (:expanded @state) "Hide" "Show")))
+        (when (:expanded @state)
+          (cond
+            (nil? data)
+              (spinner (str "Loading " (:label props) "...")) ;; show a spinner while data from the onClick loads
+            (not (:success? data))
+              (style/create-inline-error-message (:response data))
+            :else
+              ;; some portions of the metadata response from Cromwell are escaped json strings (e.g. submittedFiles/inputs),
+              ;; instead of valid json. Handle that transparently here: if we detect the target data is a string, attempt to parse it.
+              (let [raw-data (get-in data (cons :response data-path))
+                    usable-data (if (string? raw-data) (utils/parse-json-string raw-data) raw-data)]
+                (if (empty? usable-data)
+                  [:div {:style {:padding "0.25em 0 0.5em 1em" :font-style "italic"}} (str "No " (:label props) ".")]
+                  [:div {:style {:padding "0.25em 0 0.25em 1em"}}
+                    (let [namespace (get-in props [:workspace-id :namespace])
+                          columns [{:header "Label"
+                                    :column-data #(last (string/split (key %) #"\."))}
+                                   {:header "Value"
+                                    :initial-width :auto
+                                    :sortable? false
+                                    :column-data #(display-value namespace (second %))}]
+                          task-column {:header "Task"
+                                       :column-data #(second (rseq (string/split (key %) #"\.")))}]
+                      [Table
+                       {:data usable-data
+                        :body {:style table-style/table-heavy
+                               :behavior {:reorderable-columns? false
+                                          :filterable? false}
+                               :columns (if (:call-detail? props) columns (cons task-column columns))}}])]))))]))})
 
 (react/defc- WorkflowTimingDiagram
   {:render

         (let [workflow-path-prefix [(:bucketName props) (:submission-id props)]]
           (render-workflow-detail (:response metadata-response) (:raw-response metadata-response)
                                   (:workflow-name props) (:submission-id props) (:use-call-cache props)
                                   (:workspace-id props) workflow-path-prefix)))))
   :component-did-mount
   (fn [{:keys [props state]}]
     (endpoints/call-ajax-orch

                      (let [subworkflow-path-prefix (if (>= (data "shardIndex") 0)
                                                      (conj call-path-components (str "shard-" index))
                                                      call-path-components)]
                        [WorkflowDetails (merge (select-keys props [:workspace-id :submission-id :use-call-cache :workflow-name
                                                                       :inputs-fn :inputs-data :outputs-fn :outputs-data])
                                                   {:subworkflow? true
                                                    :workflow-id subWorkflowId
                                                    :gcs-path-prefix subworkflow-path-prefix})])]
                     ;; click to show subworkflow details and add it to the :subworkflow-expanded map in @state
                     (links/create-internal {:onClick #(swap! state assoc-in
