Skip to content

Commit

Permalink
feat(select): add shouldAutofocusOption prop
Browse files Browse the repository at this point in the history
  • Loading branch information
TotomInc committed Nov 17, 2024
1 parent 5bfb097 commit bacde30
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 1 deletion.
8 changes: 8 additions & 0 deletions docs/props.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,14 @@ Whether the select should allow multiple selections. If `true`, the `v-model` sh

Whether the select should display a loading state. When `true`, the select will show a loading spinner or custom loading content provided via the `loading` slot.

## shouldAutofocusOption

**Type**: `boolean`

**Default**: `true`

Whether the first option should be focused when the dropdown is opened. If set to `false`, the first option will not be focused, and the user will have to navigate through the options using the keyboard.

## closeOnSelect

**Type**: `boolean`
Expand Down
24 changes: 24 additions & 0 deletions src/Select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,14 @@ describe("single-select option", () => {

expect(wrapper.emitted("update:modelValue")).toBeUndefined();
});

it("should autofocus the first option when opening the menu, by default", async () => {
const wrapper = mount(VueSelect, { props: { modelValue: null, options } });

await openMenu(wrapper);

expect(wrapper.get(".focused[role='option']").text()).toBe(options[0].label);
});
});

describe("multi-select options", () => {
Expand Down Expand Up @@ -336,6 +344,14 @@ describe("multi-select options", () => {
expect(wrapper.findAll(".menu-option").length).toBe(options.length);
expect(wrapper.findAll(".multi-value").length).toBe(0);
});

it("should autofocus the first option when opening the menu, by default", async () => {
const wrapper = mount(VueSelect, { props: { modelValue: [], isMulti: true, options } });

await openMenu(wrapper);

expect(wrapper.get(".focused[role='option']").text()).toBe(options[0].label);
});
});

describe("clear button", () => {
Expand Down Expand Up @@ -411,4 +427,12 @@ describe("component props", () => {

expect(wrapper.findAll("div[role='option']").length).toBe(options.length);
});

it("should not autofocus an option when passing the autofocus prop", async () => {
const wrapper = mount(VueSelect, { props: { modelValue: null, options, shouldAutofocusOption: false } });

await openMenu(wrapper);

expect(wrapper.findAll(".focused[role='option']")).toHaveLength(0);
});
});
11 changes: 10 additions & 1 deletion src/Select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ const props = withDefaults(
* when fetching the options asynchronously.
*/
isLoading?: boolean;
/**
* When set to true, focus the first option when the menu is opened.
* When set to false, no option will be focused.
*/
shouldAutofocusOption?: boolean;
/**
* When set to true, clear the search input when an option is selected.
*/
Expand Down Expand Up @@ -98,6 +103,7 @@ const props = withDefaults(
isSearchable: true,
isMulti: false,
isLoading: false,
shouldAutofocusOption: true,
closeOnSelect: true,
teleport: undefined,
inputId: undefined,
Expand Down Expand Up @@ -171,7 +177,10 @@ const selectedOptions = computed(() => {
const openMenu = (options?: { focusInput?: boolean }) => {
menuOpen.value = true;
focusedOption.value = props.options.findIndex((option) => !option.disabled);
if (props.shouldAutofocusOption) {
focusedOption.value = props.options.findIndex((option) => !option.disabled);
}
if (options?.focusInput && input.value) {
input.value.focus();
Expand Down

0 comments on commit bacde30

Please sign in to comment.