diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx b/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx
index cada93d11f..5940e22e29 100644
--- a/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx
@@ -22,6 +22,7 @@ import {
type DropdownProps = {
aria?: { [key: string]: string };
autocomplete?: boolean;
+ blankSelection?: string;
children?: React.ReactChild[] | React.ReactChild | React.ReactElement[];
className?: string;
dark?: boolean;
@@ -41,6 +42,7 @@ const Dropdown = (props: DropdownProps) => {
const {
aria = {},
autocomplete = false,
+ blankSelection = '',
children,
className,
dark = false,
@@ -118,11 +120,12 @@ const Dropdown = (props: DropdownProps) => {
setIsDropDownClosed(isClosed)
}, [isClosed])
- const filteredOptions = options?.filter((option: GenericObject) => {
+ const blankSelectionOption: GenericObject = blankSelection ? [{ label: blankSelection, value: "" }] : [];
+ const optionsWithBlankSelection = blankSelectionOption.concat(options);
+ const filteredOptions = optionsWithBlankSelection?.filter((option: GenericObject) => {
const label = typeof option.label === 'string' ? option.label.toLowerCase() : option.label;
return String(label).toLowerCase().includes(filterItem.toLowerCase());
- }
- );
+ });
// For keyboard accessibility: Set focus within dropdown to selected item if it exists
useEffect(() => {
@@ -196,7 +199,7 @@ const Dropdown = (props: DropdownProps) => {
inputWrapperRef,
isDropDownClosed,
isInputFocused,
- options,
+ optionsWithBlankSelection,
selected,
setFocusedOptionIndex,
setIsDropDownClosed,
@@ -235,8 +238,8 @@ const Dropdown = (props: DropdownProps) => {
<>
- {options &&
- options?.map((option: GenericObject) => (
+ {optionsWithBlankSelection &&
+ optionsWithBlankSelection?.map((option: GenericObject) => (
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.html.erb b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.html.erb
new file mode 100644
index 0000000000..e3405df84a
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.html.erb
@@ -0,0 +1,10 @@
+<%
+ options = [
+ { label: 'United States', value: 'United States', id: 'us' },
+ { label: 'Canada', value: 'Canada', id: 'ca' },
+ { label: 'Pakistan', value: 'Pakistan', id: 'pk' },
+ ]
+
+%>
+
+<%= pb_rails("dropdown", props: { blank_selection: "Select One...", options: options }) %>
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.jsx b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.jsx
new file mode 100644
index 0000000000..a73a5e8c6a
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_blank_selection.jsx
@@ -0,0 +1,31 @@
+import React from 'react'
+import { Dropdown } from '../../'
+
+const DropdownBlankSelection = (props) => {
+ const options = [
+ {
+ label: "United States",
+ value: "United States",
+ },
+ {
+ label: "Canada",
+ value: "Canada",
+ },
+ {
+ label: "Pakistan",
+ value: "Pakistan",
+ }
+ ];
+
+ return (
+ <>
+
+ >
+ )
+}
+
+export default DropdownBlankSelection
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml b/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml
index 267b06e0fc..5f4d445870 100644
--- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml
@@ -9,6 +9,7 @@ examples:
- dropdown_with_custom_padding: Custom Option Padding
- dropdown_error: Dropdown with Error
- dropdown_default_value: Default Value
+ - dropdown_blank_selection: Blank Selection
react:
- dropdown_default: Default
@@ -20,6 +21,7 @@ examples:
- dropdown_with_custom_padding: Custom Option Padding
- dropdown_error: Dropdown with Error
- dropdown_default_value: Default Value
+ - dropdown_blank_selection: Blank Selection
# - dropdown_with_autocomplete: Autocomplete
# - dropdown_with_autocomplete_and_custom_display: Autocomplete with Custom Display
# - dropdown_with_external_control: useDropdown Hook
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js b/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js
index 451a930ef9..92feffe44a 100644
--- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js
@@ -10,4 +10,5 @@ export { default as DropdownWithExternalControl } from './_dropdown_with_externa
export { default as DropdownWithHook } from './_dropdown_with_hook.jsx'
export { default as DropdownSubcomponentStructure } from './_dropdown_subcomponent_structure.jsx'
export { default as DropdownError } from './_dropdown_error.jsx'
-export { default as DropdownDefaultValue } from './_dropdown_default_value.jsx'
\ No newline at end of file
+export { default as DropdownDefaultValue } from './_dropdown_default_value.jsx'
+export { default as DropdownBlankSelection } from './_dropdown_blank_selection.jsx'
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb
index 9586c12c5d..fc2a261045 100644
--- a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb
@@ -17,8 +17,8 @@
<% else %>
<%= pb_rails("dropdown/dropdown_trigger") %>
<%= pb_rails("dropdown/dropdown_container") do %>
- <% if object.options.present? %>
- <% object.options.each do |option| %>
+ <% if options_with_blank.present? %>
+ <% options_with_blank.each do |option| %>
<%= pb_rails("dropdown/dropdown_option", props: {option: option}) %>
<% end %>
<% end %>
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb
index 48a6988b2b..d390b7e015 100644
--- a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb
@@ -11,6 +11,8 @@ class Dropdown < Playbook::KitBase
prop :required, type: Playbook::Props::Boolean,
default: false
prop :default_value
+ prop :blank_selection, type: Playbook::Props::String,
+ default: ""
def data
Hash(prop(:data)).merge(pb_dropdown: true)
@@ -29,6 +31,10 @@ def error_class
def input_default_value
default_value.present? ? default_value.transform_keys(&:to_s) : ""
end
+
+ def options_with_blank
+ blank_selection.present? ? [{ id: "", value: "", label: blank_selection }] + options : options
+ end
end
end
end
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb
index 84fb4a2c8f..e34e562dbf 100644
--- a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown_trigger.rb
@@ -11,7 +11,7 @@ class DropdownTrigger < Playbook::KitBase
prop :custom_display
def data
- Hash(prop(:data)).merge(dropdown_trigger: true)
+ Hash(prop(:data)).merge(dropdown_trigger: true, dropdown_placeholder: default_display_placeholder)
end
def classname
diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/index.js b/playbook/app/pb_kits/playbook/pb_dropdown/index.js
index 6035afa4c5..42219cda92 100644
--- a/playbook/app/pb_kits/playbook/pb_dropdown/index.js
+++ b/playbook/app/pb_kits/playbook/pb_dropdown/index.js
@@ -9,6 +9,8 @@ const UP_ARROW_SELECTOR = "#dropdown_close_icon";
const OPTION_SELECTOR = "[data-dropdown-option-label]";
const CUSTOM_DISPLAY_SELECTOR = "[data-dropdown-custom-trigger]";
const INPUT_FORM_VALIDATION = "#dropdown-form-validation";
+const DROPDOWN_TRIGGER_DISPLAY = "#dropdown_trigger_display";
+const DROPDOWN_PLACEHOLDER = "[data-dropdown-placeholder]";
export default class PbDropdown extends PbEnhancedElement {
static get selector() {
@@ -25,6 +27,7 @@ export default class PbDropdown extends PbEnhancedElement {
this.bindEventListeners();
this.updateArrowDisplay(false);
this.handleFormValidation();
+ this.handleFormReset();
}
bindEventListeners() {
@@ -84,9 +87,7 @@ export default class PbDropdown extends PbEnhancedElement {
}
onOptionSelected(value, selectedOption) {
- const triggerElement = this.element.querySelector(
- "#dropdown_trigger_display"
- );
+ const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
const customDisplayElement = this.element.querySelector(
"#dropdown_trigger_custom_display"
);
@@ -195,13 +196,38 @@ export default class PbDropdown extends PbEnhancedElement {
}
});
- const triggerElement = this.element.querySelector("#dropdown_trigger_display");
- if (triggerElement) {
- triggerElement.textContent = defaultValue.label;
- }
+ this.setTriggerElementText(defaultValue.label);
hiddenInput.value = defaultValue.id;
inputFormValidation.value = defaultValue.id;
}
}
+
+ handleFormReset() {
+ const form = this.element.closest("form");
+
+ if (form) {
+ form.addEventListener("reset", () => {
+ this.resetDropdownValue();
+ });
+ }
+ }
+
+ resetDropdownValue() {
+ const hiddenInput = this.element.querySelector("#dropdown-selected-option");
+ const inputFormValidation = this.element.querySelector(INPUT_FORM_VALIDATION);
+
+ hiddenInput.value = "";
+ inputFormValidation.value = "";
+
+ const defaultPlaceholder = this.element.querySelector(DROPDOWN_PLACEHOLDER);
+ this.setTriggerElementText(defaultPlaceholder.dataset.dropdownPlaceholder);
+ }
+
+ setTriggerElementText(text) {
+ const triggerElement = this.element.querySelector(DROPDOWN_TRIGGER_DISPLAY);
+ if (triggerElement) {
+ triggerElement.textContent = text;
+ }
+ }
}