diff --git a/apps/website/screens/components/select/code/SelectCodePage.tsx b/apps/website/screens/components/select/code/SelectCodePage.tsx
index 502d7f507..82ed44dbb 100644
--- a/apps/website/screens/components/select/code/SelectCodePage.tsx
+++ b/apps/website/screens/components/select/code/SelectCodePage.tsx
@@ -255,6 +255,22 @@ const sections = [
false
+
| size |
diff --git a/packages/lib/src/select/Select.stories.tsx b/packages/lib/src/select/Select.stories.tsx
index bb15eee65..097f1482c 100644
--- a/packages/lib/src/select/Select.stories.tsx
+++ b/packages/lib/src/select/Select.stories.tsx
@@ -35,6 +35,13 @@ const singleOptions = [
{ label: "Option 04", value: "4" },
];
+const startsWithSingleOptions = [
+ { label: "Option 01", value: "1" },
+ { label: "This is option 02", value: "2" },
+ { label: "Is option 03", value: "3" },
+ { label: "And Option 04", value: "4" },
+];
+
const single_options_virtualized = [
...Array.from({ length: 10000 }, (_, i) => ({
label: `Option ${String(i + 1).padStart(2, "0")}`,
@@ -593,6 +600,19 @@ const SearchableSelect = () => (
);
+const startsWithSearchableSelect = () => (
+
+
+
+
+);
+
const SearchValue = () => (
@@ -740,6 +760,14 @@ export const Searchable: Story = {
},
};
+export const StartsWithSearchable: Story = {
+ render: startsWithSearchableSelect,
+ play: async ({ canvasElement }) => {
+ const canvas = within(canvasElement);
+ await userEvent.type(await canvas.findByRole("combobox"), "t");
+ },
+};
+
export const SearchableWithValue: Story = {
render: SearchValue,
play: async ({ canvasElement }) => {
diff --git a/packages/lib/src/select/Select.tsx b/packages/lib/src/select/Select.tsx
index 1a044ce52..5fa9a0e82 100644
--- a/packages/lib/src/select/Select.tsx
+++ b/packages/lib/src/select/Select.tsx
@@ -191,6 +191,7 @@ const DxcSelect = forwardRef(
options,
placeholder = "",
searchable = false,
+ searchByStartsWith = false,
size = "medium",
tabIndex = 0,
value,
@@ -217,7 +218,10 @@ const DxcSelect = forwardRef(
const translatedLabels = useContext(HalstackLanguageContext);
const optionalItem = useMemo(() => ({ label: placeholder, value: "" }), [placeholder]);
- const filteredOptions = useMemo(() => filterOptionsBySearchValue(options, searchValue), [options, searchValue]);
+ const filteredOptions = useMemo(
+ () => filterOptionsBySearchValue(options, searchValue, searchByStartsWith),
+ [options, searchValue, searchByStartsWith]
+ );
const lastOptionIndex = useMemo(
() => getLastOptionIndex(options, filteredOptions, searchable, optional, multiple, enableSelectAll),
[options, filteredOptions, searchable, optional, multiple, enableSelectAll]
diff --git a/packages/lib/src/select/types.ts b/packages/lib/src/select/types.ts
index 0ea85c328..adcea907f 100644
--- a/packages/lib/src/select/types.ts
+++ b/packages/lib/src/select/types.ts
@@ -91,6 +91,12 @@ type CommonProps = {
* If true, enables search functionality.
*/
searchable?: boolean;
+ /**
+ * Defines the search mode when searchable is true.
+ * If true, matches options that start with the search text.
+ * If false, matches options that contain the search text anywhere in their label.
+ */
+ searchByStartsWith?: boolean;
/**
* Size of the component.
*/
diff --git a/packages/lib/src/select/utils.ts b/packages/lib/src/select/utils.ts
index 83af7d14b..1720aa34e 100644
--- a/packages/lib/src/select/utils.ts
+++ b/packages/lib/src/select/utils.ts
@@ -51,20 +51,31 @@ export const canOpenListbox = (options: Props["options"], disabled: boolean) =>
/**
* Filters the options by the search value.
*/
-export const filterOptionsBySearchValue = (options: Props["options"], searchValue: string): Props["options"] =>
- options.length > 0
+export const filterOptionsBySearchValue = (
+ options: Props["options"],
+ searchValue: string,
+ searchByStartsWith: Props["searchByStartsWith"] = false
+): Props["options"] => {
+ const matchesSearch = (label: string, search: string, searchByStartsWith: boolean) => {
+ const upperLabel = label.toUpperCase();
+ const upperSearch = search.toUpperCase();
+ return searchByStartsWith ? upperLabel.startsWith(upperSearch) : upperLabel.includes(upperSearch);
+ };
+
+ return options.length > 0
? isArrayOfGroupedOptions(options)
? options.map((optionGroup) => {
const group = {
label: optionGroup.label,
options: optionGroup.options.filter((option) =>
- option.label.toUpperCase().includes(searchValue.toUpperCase())
+ matchesSearch(option.label, searchValue, searchByStartsWith)
),
};
return group;
})
- : options.filter((option) => option.label.toUpperCase().includes(searchValue.toUpperCase()))
+ : options.filter((option) => matchesSearch(option.label, searchValue, searchByStartsWith))
: [];
+};
/**
* Returns the index of the last option, depending on several conditions.
|