diff --git a/playbook/app/entrypoints/playbook-rails.js b/playbook/app/entrypoints/playbook-rails.js
index 6c11e2a8a8..7769cb5fb9 100644
--- a/playbook/app/entrypoints/playbook-rails.js
+++ b/playbook/app/entrypoints/playbook-rails.js
@@ -1,5 +1,7 @@
// Forms
import 'kits/pb_form/pb_form_validation'
+import formHelper from 'kits/pb_form/formHelper'
+window.formHelper = formHelper
// Date Picker
import datePickerHelper from 'kits/pb_date_picker/date_picker_helper'
diff --git a/playbook/app/javascript/plugins.js b/playbook/app/javascript/plugins.js
index d27f3cec4a..0ecdf5e1e6 100644
--- a/playbook/app/javascript/plugins.js
+++ b/playbook/app/javascript/plugins.js
@@ -6,3 +6,5 @@ export { default as PbTextarea } from '../pb_kits/playbook/pb_textarea'
export { default as PbTooltip } from '../pb_kits/playbook/pb_tooltip'
export { default as PbTypeahead } from '../pb_kits/playbook/pb_typeahead'
export { default as dialogHelper } from '../pb_kits/playbook/pb_dialog/dialogHelper'
+export { default as formHelper } from '../pb_kits/playbook/pb_form/formHelper'
+
diff --git a/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.html.erb b/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.html.erb
index 5d8254f492..764f0d9559 100644
--- a/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.html.erb
+++ b/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.html.erb
@@ -1,13 +1,36 @@
<%= pb_rails("button", props: { text: "Open Dialog", data: {"open-dialog": "dialog-loading"} }) %>
-<%= pb_rails("dialog", props: {
- id:"dialog-loading",
- size: "sm",
- title: "Loading Exmaple",
- text: "Make a loading request?",
- cancel_button: "Cancel Button",
+<%= pb_rails("dialog", props: {
+ id:"dialog-loading",
+ size: "sm",
+ title: "Loading Example",
+ text: "Make a loading request?",
+ cancel_button: "Cancel Button",
cancel_button_id: "cancel-button-loading",
- confirm_button: "Okay",
+ confirm_button: "Okay",
confirm_button_id: "confirm-button-loading",
loading: true,
}) %>
+
+
diff --git a/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md b/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md
index ad7fbfab33..de0f291d1a 100644
--- a/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md
+++ b/playbook/app/pb_kits/playbook/pb_dialog/docs/_dialog_loading.md
@@ -1,3 +1 @@
Pressing the "Okay" button will trigger a loading state where the button content is replaced by a spinner icon and both buttons are disabled.
-
-Currently, the loading state cannot be undone and will require a page refresh to reset the dialog.
diff --git a/playbook/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb b/playbook/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb
new file mode 100644
index 0000000000..e0702b1303
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.html.erb
@@ -0,0 +1,39 @@
+<%= pb_form_with(scope: :example, url: "", method: :get, loading: true) do |form| %>
+ <%= form.text_field :example_text_field, props: { label: true } %>
+
+ <%= form.actions do |action| %>
+ <%= action.submit %>
+ <%= action.button props: { type: "reset", text: "Cancel", variant: "secondary" } %>
+ <% end %>
+<% end %>
+
+
+
diff --git a/playbook/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md b/playbook/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md
new file mode 100644
index 0000000000..eef1260771
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_form/docs/_form_form_with_loading.md
@@ -0,0 +1 @@
+Pressing Submit will trigger a loading state where the button content is replaced by a spinner icon and the submit button will be disabled.
diff --git a/playbook/app/pb_kits/playbook/pb_form/docs/example.yml b/playbook/app/pb_kits/playbook/pb_form/docs/example.yml
index b04c3fdc51..19f029d494 100644
--- a/playbook/app/pb_kits/playbook/pb_form/docs/example.yml
+++ b/playbook/app/pb_kits/playbook/pb_form/docs/example.yml
@@ -3,3 +3,4 @@ examples:
rails:
- form_form_with: Default
- form_form_with_validate: Default + Validation
+ - form_form_with_loading: Default + Loading
diff --git a/playbook/app/pb_kits/playbook/pb_form/form.rb b/playbook/app/pb_kits/playbook/pb_form/form.rb
index dc7b2574dd..d931173922 100644
--- a/playbook/app/pb_kits/playbook/pb_form/form.rb
+++ b/playbook/app/pb_kits/playbook/pb_form/form.rb
@@ -7,6 +7,7 @@ class Form < ::Playbook::KitBase
type: Playbook::Props::Base
prop :form_system_options, deprecated: "Use options instead",
type: Playbook::Props::Base
+ prop :loading, type: Playbook::Props::Boolean, default: false
prop :options, type: Playbook::Props::Base
prop :validate, type: Playbook::Props::Boolean, default: false
@@ -22,6 +23,7 @@ def form_options
aria: aria,
class: classname,
data: data,
+ loading: loading,
validate: validate,
}.merge(prop(:options) || prop(:form_system_options) || {})
end
diff --git a/playbook/app/pb_kits/playbook/pb_form/formHelper.js b/playbook/app/pb_kits/playbook/pb_form/formHelper.js
new file mode 100644
index 0000000000..1c0fdb72d1
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_form/formHelper.js
@@ -0,0 +1,27 @@
+const formHelper = () => {
+ const loadingForm = document.querySelector(".pb_form_loading")
+ if (loadingForm) {
+ loadingForm.addEventListener("submit", function(event) {
+ const submitButton = event['submitter'];
+ const cancelButton = event['target'].querySelector('button[type="reset"]');
+
+ if (submitButton) {
+ let currentClass = submitButton.className;
+ let newClass = currentClass.replace("_enabled", "_disabled_loading");
+
+ let cancelClass = cancelButton ? cancelButton.className : "";
+ let newCancelClass = cancelClass.replace("_enabled", "_disabled");
+
+ submitButton.disabled = true;
+ submitButton.className = newClass;
+
+ if (cancelButton) {
+ cancelButton.disabled = true;
+ cancelButton.className = newCancelClass;
+ }
+ }
+ });
+ }
+};
+
+export default formHelper;
diff --git a/playbook/lib/playbook/pb_forms_helper.rb b/playbook/lib/playbook/pb_forms_helper.rb
index c2b4c11d7a..f515b5db13 100755
--- a/playbook/lib/playbook/pb_forms_helper.rb
+++ b/playbook/lib/playbook/pb_forms_helper.rb
@@ -22,9 +22,10 @@ module PbFormsHelper
# @param data [Hash] hash of data attributes
# @param validate [Boolean] whether validation should be triggered or not
# @see [#form_with] for other options
- def pb_form_with(data: {}, validate: false, **kwargs, &block)
+ def pb_form_with(data: {}, validate: false, loading: false, **kwargs, &block)
data = data.merge("pb-form-validation" => validate)
classname = ["pb-form", kwargs[:class]].join(" ")
+ classname += " pb_form_loading" if loading
options = kwargs.merge(
class: classname,
data: data,
@@ -33,6 +34,7 @@ def pb_form_with(data: {}, validate: false, **kwargs, &block)
content_for(:pb_js, javascript_tag(<<~JS))
window.addEventListener("DOMContentLoaded", function() { PbFormValidation.start() })
+ window.addEventListener("DOMContentLoaded", () => formHelper())
JS
form_with(**options, &block)