Skip to content

feat(select): add shouldAutofocusOption prop #134

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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