+ Autoloading components via projects is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
+
- Autoloading components via projects is the recommended way to import components. If you prefer to do it manually, use one of the following code snippets.
-
- To manually import this component from React, use the following code.
-
-
import {{ component.name }} from '@awesome.me/webawesome/dist/react/{{ componentName }}';
-
-
-
diff --git a/packages/webawesome/docs/docs/components/select.md b/packages/webawesome/docs/docs/components/select.md
index ff7135e8a..2878fc00b 100644
--- a/packages/webawesome/docs/docs/components/select.md
+++ b/packages/webawesome/docs/docs/components/select.md
@@ -285,9 +285,10 @@ Remember that custom tags are rendered in a shadow root. To style them, you can
const name = option.querySelector('wa-icon[slot="start"]').name;
// You can return a string, a Lit Template, or an HTMLElement here
+ // Important: include data-value so the tag can be removed properly!
return `
-
-
+
+
${option.label}
`;
@@ -299,6 +300,10 @@ Remember that custom tags are rendered in a shadow root. To style them, you can
Be sure you trust the content you are outputting! Passing unsanitized user input to `getTag()` can result in XSS vulnerabilities.
:::
+:::info
+When using custom tags with `with-remove`, you must include the `data-value` attribute set to the option's value. This allows the select to identify which option to deselect when the tag's remove button is clicked.
+:::
+
### Lazy loading options
Lazy loading options works similarly to native `
@@ -520,6 +523,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
event.stopPropagation();
if (this.value !== null) {
+ this.selectionOrder.clear();
this.setSelectedOptions([]);
this.displayInput.focus({ preventScroll: true });
@@ -603,24 +607,20 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
if (this.disabled) return;
+ // Mark as interacted so selectionChanged() uses the correct filter logic
+ this.hasInteracted = true;
+ this.valueHasChanged = true;
+
// Use the directly provided option if available (from getTag method)
let option = directOption;
- // If no direct option was provided, find the option from the event path
+ // If no direct option was provided, find the option from the data-value attribute
if (!option) {
- const tagElement = (event.target as Element).closest('wa-tag[part~=tag]');
+ const tagElement = (event.target as Element).closest('wa-tag[data-value]') as HTMLElement | null;
if (tagElement) {
- // Find the index of this tag among all tags
- const tagsContainer = this.shadowRoot?.querySelector('[part="tags"]');
- if (tagsContainer) {
- const allTags = Array.from(tagsContainer.children);
- const index = allTags.indexOf(tagElement as HTMLElement);
-
- if (index >= 0 && index < this.selectedOptions.length) {
- option = this.selectedOptions[index];
- }
- }
+ const value = tagElement.dataset.value;
+ option = this.selectedOptions.find(opt => opt.value === value);
}
}
@@ -707,7 +707,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
const options = this.getAllOptions();
// Update selected options cache
- this.selectedOptions = options.filter(el => {
+ const newSelectedOptions = options.filter(el => {
if (!this.hasInteracted && !this.valueHasChanged) {
const defaultValue = this.defaultValue;
const defaultValues = Array.isArray(defaultValue) ? defaultValue : [defaultValue];
@@ -717,6 +717,32 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
return el.selected;
});
+ // Update the selection order map
+ const newSelectedValues = new Set(newSelectedOptions.map(el => el.value));
+
+ // Remove deselected options from the order map
+ for (const value of this.selectionOrder.keys()) {
+ if (!newSelectedValues.has(value)) {
+ this.selectionOrder.delete(value);
+ }
+ }
+
+ // Add newly selected options
+ const maxOrder = this.selectionOrder.size > 0 ? Math.max(...this.selectionOrder.values()) : -1;
+ let nextOrder = maxOrder + 1;
+ for (const option of newSelectedOptions) {
+ if (!this.selectionOrder.has(option.value)) {
+ this.selectionOrder.set(option.value, nextOrder++);
+ }
+ }
+
+ // Sort options by selection order
+ this.selectedOptions = newSelectedOptions.sort((a, b) => {
+ const orderA = this.selectionOrder.get(a.value) ?? 0;
+ const orderB = this.selectionOrder.get(b.value) ?? 0;
+ return orderA - orderB;
+ });
+
let selectedValues = new Set(this.selectedOptions.map(el => el.value));
// Toggle values present in the DOM from this.value, while preserving options NOT present in the DOM (for lazy loading)
@@ -888,6 +914,7 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
}
formResetCallback() {
+ this.selectionOrder.clear();
this.value = this.defaultValue;
super.formResetCallback();
this.handleValueChange();