diff --git a/packages/main/cypress/specs/ToolbarSelect.cy.tsx b/packages/main/cypress/specs/ToolbarSelect.cy.tsx
index f7c1fef6a698c..45ee9c7aa3685 100644
--- a/packages/main/cypress/specs/ToolbarSelect.cy.tsx
+++ b/packages/main/cypress/specs/ToolbarSelect.cy.tsx
@@ -111,6 +111,243 @@ describe("Toolbar general interaction", () => {
.should("have.attr", "accessible-name-ref", "title");
});
+ it("Should expose value and selectedToolbarOption in change event detail", () => {
+ cy.mount(
+ <>
+
+
+ Option 1
+ Option 2
+ Option 3
+
+
+
+
+ >
+ );
+
+ cy.get("[ui5-toolbar-select]").then($select => {
+ $select.get(0).addEventListener("ui5-change", (e: Event) => {
+ const ce = e as CustomEvent;
+ (document.querySelector("[data-testid='result-value']") as HTMLInputElement).value = ce.detail.selectedOption.value;
+ (document.querySelector("[data-testid='result-toolbar-option']") as HTMLInputElement).value = ce.detail.selectedToolbarOption.value;
+ });
+ });
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realClick();
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("ArrowUp");
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("Enter");
+
+ cy.get("[data-testid='result-value']").should("have.prop", "value", "opt1");
+ cy.get("[data-testid='result-toolbar-option']").should("have.prop", "value", "opt1");
+ });
+
+ it("Should expose selectedToolbarOption as the actual element reference with correct id and value", () => {
+ cy.mount(
+ <>
+
+
+ First
+ Second
+ Third
+
+
+
+ >
+ );
+
+ cy.get("[ui5-toolbar-select]").then($select => {
+ $select.get(0).addEventListener("ui5-change", (e: Event) => {
+ const ce = e as CustomEvent;
+ const selectedToolbarOption = ce.detail.selectedToolbarOption as HTMLElement;
+ const testDiv = document.querySelector("[data-testid='selected-element-id']") as HTMLElement;
+ testDiv.setAttribute("data-selected-id", selectedToolbarOption.id);
+ testDiv.setAttribute("data-selected-value", (selectedToolbarOption as any).value || "");
+ });
+ });
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realClick();
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("ArrowDown");
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("Enter");
+
+ cy.get("[data-testid='selected-element-id']")
+ .should("have.attr", "data-selected-id", "opt-3")
+ .should("have.attr", "data-selected-value", "value3");
+ });
+
+ it("Should correctly identify selectedToolbarOption when option text does not match value", () => {
+ cy.mount(
+ <>
+
+
+ Display Text 1
+ Display Text 2
+ Display Text 3
+
+
+
+
+ >
+ );
+
+ cy.get("[ui5-toolbar-select]").then($select => {
+ $select.get(0).addEventListener("ui5-change", (e: Event) => {
+ const ce = e as CustomEvent;
+ const selectedToolbarOption = ce.detail.selectedToolbarOption as any;
+ (document.querySelector("[data-testid='value-match-test']") as HTMLInputElement).value = selectedToolbarOption.value || "";
+ (document.querySelector("[data-testid='text-match-test']") as HTMLInputElement).value = selectedToolbarOption.textContent?.trim() || "";
+ });
+ });
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realClick();
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("ArrowDown");
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("Enter");
+
+ cy.get("[data-testid='value-match-test']").should("have.prop", "value", "internal_3");
+ cy.get("[data-testid='text-match-test']").should("have.prop", "value", "Display Text 3");
+ });
+
+ it("Should expose correct selectedToolbarOption for duplicate text options", () => {
+ cy.mount(
+ <>
+
+
+ Pending
+ Active
+ Pending
+
+
+
+ >
+ );
+
+ cy.get("[ui5-toolbar-select]").then($select => {
+ $select.get(0).addEventListener("ui5-change", (e: Event) => {
+ const ce = e as CustomEvent;
+ (document.querySelector("[data-testid='dup-result-value']") as HTMLInputElement).value = ce.detail.selectedToolbarOption.value;
+ });
+ });
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realClick();
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("ArrowDown");
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("ArrowDown");
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("Enter");
+
+ cy.get("[data-testid='dup-result-value']").should("have.prop", "value", "pending-urgent");
+ });
+
+ it("Should work correctly when options have no value property set", () => {
+ cy.mount(
+ <>
+
+
+ Option A
+ Option B
+ Option C
+
+
+
+ >
+ );
+
+ cy.get("[ui5-toolbar-select]").then($select => {
+ $select.get(0).addEventListener("ui5-change", (e: Event) => {
+ const ce = e as CustomEvent;
+ (document.querySelector("[data-testid='no-value-result']") as HTMLInputElement).value = ce.detail.selectedToolbarOption.textContent?.trim() ?? "";
+ });
+ });
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realClick();
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("ArrowDown");
+
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .realPress("Enter");
+
+ cy.get("[data-testid='no-value-result']").should("have.prop", "value", "Option B");
+
+ // Verify the internal select still shows the correct option selected
+ cy.get("[ui5-toolbar]")
+ .find("[ui5-toolbar-select]")
+ .shadow()
+ .find("[ui5-select]")
+ .find("[ui5-option]")
+ .eq(1)
+ .should("have.attr", "selected");
+ });
+
it("Should fire change event on selection change", () => {
cy.mount(
<>
diff --git a/packages/main/src/ToolbarSelect.ts b/packages/main/src/ToolbarSelect.ts
index 5885a16ade5f3..74fde918b1adf 100644
--- a/packages/main/src/ToolbarSelect.ts
+++ b/packages/main/src/ToolbarSelect.ts
@@ -15,7 +15,9 @@ import type ToolbarSelectOption from "./ToolbarSelectOption.js";
import type { SelectChangeEventDetail } from "./Select.js";
import type { DefaultSlot, Slot } from "@ui5/webcomponents-base/dist/UI5Element.js";
-type ToolbarSelectChangeEventDetail = ToolbarItemEventDetail & SelectChangeEventDetail;
+type ToolbarSelectChangeEventDetail = ToolbarItemEventDetail & SelectChangeEventDetail & {
+ selectedToolbarOption: ToolbarSelectOption | undefined;
+};
/**
* @class
@@ -44,6 +46,8 @@ type ToolbarSelectChangeEventDetail = ToolbarItemEventDetail & SelectChangeEvent
/**
* Fired when the selected option changes.
* @param {HTMLElement} selectedOption the selected option.
+ * @param {HTMLElement} selectedToolbarOption the original toolbar select option.
+ * @since 2.25.0
* @public
*/
@event("change", {
@@ -193,16 +197,17 @@ class ToolbarSelect extends ToolbarItemBase {
onChange(e: CustomEvent): void {
e.stopImmediatePropagation();
- const prevented = !this.fireDecoratorEvent("change", { ...e.detail, targetRef: e.target as HTMLElement });
+ const selectedOptionIndex = Number(e.detail.selectedOption?.getAttribute("data-ui5-external-action-item-index"));
+ const selectedToolbarOption = this.options[selectedOptionIndex];
+ const prevented = !this.fireDecoratorEvent("change", { ...e.detail, targetRef: e.target as HTMLElement, selectedToolbarOption });
if (!prevented) {
this.fireDecoratorEvent("close-overflow");
}
- this._syncOptions(e.detail.selectedOption);
+ this._syncOptions(selectedOptionIndex);
}
- _syncOptions(selectedOption: HTMLElement): void {
- const selectedOptionIndex = Number(selectedOption?.getAttribute("data-ui5-external-action-item-index"));
+ _syncOptions(selectedOptionIndex: number): void {
this.options.forEach((option: ToolbarSelectOption, index: number) => {
option.selected = index === selectedOptionIndex;
});
diff --git a/packages/main/src/ToolbarSelectOption.ts b/packages/main/src/ToolbarSelectOption.ts
index d89aed22e6975..9c324c8fa70a5 100644
--- a/packages/main/src/ToolbarSelectOption.ts
+++ b/packages/main/src/ToolbarSelectOption.ts
@@ -19,6 +19,15 @@ import type ToolbarSelect from "./ToolbarSelect.js";
*/
@customElement("ui5-toolbar-select-option")
class ToolbarSelectOption extends UI5Element {
+ /**
+ * Defines the value of the component.
+ * @default undefined
+ * @public
+ * @since 2.25.0
+ */
+ @property()
+ value?: string;
+
/**
* Defines the selected state of the component.
* @default false
@@ -47,7 +56,7 @@ class ToolbarSelectOption extends UI5Element {
}
});
if (parent.select) {
- parent.select.value = this.textContent || "";
+ parent.select.value = this.value !== undefined && this.value !== "" ? this.value : (this.textContent || "");
}
}
}
diff --git a/packages/main/src/ToolbarSelectTemplate.tsx b/packages/main/src/ToolbarSelectTemplate.tsx
index 28e1f2c1dc3e6..b1ffef24f03b2 100644
--- a/packages/main/src/ToolbarSelectTemplate.tsx
+++ b/packages/main/src/ToolbarSelectTemplate.tsx
@@ -25,6 +25,7 @@ export default function ToolbarSelectTemplate(this: ToolbarSelect) {
{this.options.map((option, index) => (