Skip to content

Commit 3e78bf8

Browse files
committed
fix(select): can't focus input or search when isSearchable is set to false
fixes #320
1 parent 3bc94a0 commit 3e78bf8

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

src/Select.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,28 @@ describe("component props", () => {
380380
expect(wrapper.findAll("div[role='option']").length).toBe(options.length);
381381
});
382382

383+
it("should not allow focusing or typing when isSearchable is false", async () => {
384+
const wrapper = mount(VueSelect, { props: { modelValue: null, options, isSearchable: false } });
385+
386+
const input = wrapper.get("input");
387+
388+
// Input should be readonly and removed from tab order
389+
expect(input.attributes("readonly")).toBe("");
390+
expect(input.attributes("tabindex")).toBe("-1");
391+
392+
// Focus attempt should not set focus-visible behavior or allow typing to change value
393+
await input.trigger("focus");
394+
await input.setValue("United");
395+
396+
// Menu shouldn't open due to typing, and no search event should be emitted
397+
expect(wrapper.findAll("div[role='option']").length).toBe(0);
398+
expect(wrapper.emitted("search")).toBeUndefined();
399+
400+
// Opening the menu via control still works
401+
await openMenu(wrapper, "mousedown");
402+
expect(wrapper.findAll("div[role='option']").length).toBe(options.length);
403+
});
404+
383405
it("should not autofocus an option when passing the autofocus prop", async () => {
384406
const wrapper = mount(VueSelect, { props: { modelValue: null, options, shouldAutofocusOption: false } });
385407

src/Select.vue

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,13 @@ const inputAttributes = computed(() => {
116116
type: "text",
117117
};
118118
119+
const nonSearchableAttrs = props.isSearchable
120+
? {}
121+
: { "readonly": true, "tabindex": -1, "aria-hidden": true };
122+
119123
return {
120124
...defaultAttrs,
125+
...nonSearchableAttrs,
121126
...props.inputAttrs,
122127
};
123128
});
@@ -133,7 +138,7 @@ function openMenu() {
133138
focusedOption.value = props.options.findIndex((option) => !option.disabled);
134139
}
135140
136-
if (inputRef.value) {
141+
if (props.isSearchable && inputRef.value) {
137142
inputRef.value.focus();
138143
}
139144
@@ -288,7 +293,7 @@ defineExpose({
288293
watch(
289294
() => search.value,
290295
() => {
291-
if (search.value) {
296+
if (props.isSearchable && search.value) {
292297
emit("search", search.value);
293298
294299
if (!menuOpen.value) {

0 commit comments

Comments
 (0)