Browser mode implements testing-library user-event APIs
Vitest implements a subset of @testing-library/user-event APIs using Chrome DevTools Protocol or webdriver instead of faking events, making browser behaviour more reliable and consistent with how users interact with a page. The default userEvent instance is created once, not every time its methods are called, unlike @testing-library/user-event.
userEvent.setup creates a new instance
userEvent.setup() creates a new user event instance. This is useful when you need to keep the state of keyboard to press and release buttons correctly. The signature is function setup(): UserEvent.
Keyboard state persists between interactions in Vitest
In Vitest, pressing and releasing keys happens on separate calls, not within a single method call. For example, await userEvent.keyboard('{Shift}') presses shift without releasing, and await userEvent.keyboard('{/Shift}') releases it. This keeps keyboard state across method calls, unlike @testing-library/user-event where each call resets state.
userEvent.click clicks on an element
userEvent.click(element: Element | Locator, options?: UserEventClickOptions): Promise<void> clicks on an element. The method can be called on userEvent or directly on a locator. With WebdriverIO, use an empty object argument to force using actions chain instead of ElementClick. With Playwright, use modifiers option like { modifiers: ['Shift'] } for modifier clicks.
userEvent.dblClick triggers double click
userEvent.dblClick(element: Element | Locator, options?: UserEventDoubleClickOptions): Promise<void> triggers a double click event on an element. Can be called on userEvent or directly on a locator.
userEvent.tripleClick fires three click events
userEvent.tripleClick(element: Element | Locator, options?: UserEventTripleClickOptions): Promise<void> triggers a triple click event by firing three click events in a row. Since there is no native tripleclick browser API, you must check the click event detail property (evt.detail === 3) to filter the triple click event.
userEvent.wheel triggers wheel events for scrolling
userEvent.wheel(element: Element | Locator, options: UserEventWheelOptions): Promise<void> triggers a wheel event on an element. You can specify scroll amount using delta for pixel-based control with { x, y } values, or direction for simpler directional scrolling ('up', 'down', 'left', 'right'). Use times option to trigger multiple wheel events for better performance. Wheel events can also be triggered from locators. This method is intended for UI that explicitly listens to wheel events, not for regular page scrolling.
userEvent.fill sets input value
userEvent.fill(element: Element | Locator, text: string): Promise<void> sets a value to an input/textarea/contenteditable field by removing existing text first. This method focuses the element, fills it, and triggers an input event. It does not support user-event keyboard syntax (e.g., {Shift}{selectall}). It is faster than userEvent.type but less flexible.
userEvent.keyboard triggers keyboard strokes with special key support
userEvent.keyboard(text: string): Promise<void> allows triggering keyboard strokes. If an input has focus, it types into that input; otherwise it triggers keyboard events on the currently focused element (document.body if nothing is focused). It supports user-event keyboard syntax with special keys: Modifiers ({Shift}, {Control}, {Alt}, {Meta}), Navigation ({ArrowUp}, {ArrowDown}, {ArrowLeft}, {ArrowRight}, {Home}, {End}, {PageUp}, {PageDown}), Editing ({Backspace}, {Delete}, {Insert}, {Tab}, {Enter}, {Escape}), and Function keys ({F1} through {F12}).
userEvent.tab sends Tab key event
userEvent.tab(options?: UserEventTabOptions): Promise<void> sends a Tab key event. This is a shorthand for userEvent.keyboard('{tab}'). Options can include shift: true for shift+tab.
userEvent.type types text with keyboard syntax support
userEvent.type(element: Element | Locator, text: string, options?: UserEventTypeOptions): Promise<void> types characters into an input/textarea/contenteditable element. It supports user-event keyboard syntax including special characters like {shift} or {selectall}. If you don't need special characters, use userEvent.fill for better performance.
userEvent.clear clears input element content
userEvent.clear(element: Element | Locator, options?: UserEventClearOptions): Promise<void> clears the content of an input element. Can be called on userEvent or directly on a locator.
userEvent.selectOptions selects value in select element
userEvent.selectOptions(element: Element | Locator, values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[], options?: UserEventSelectOptions): Promise<void> allows selecting a value in a <select> element. If the select element doesn't have multiple attribute, only the first element in the array is selected. Values can be HTMLElement, Locator, or string (option value or text). Vitest doesn't support listbox at the moment. WebdriverIO provider doesn't support selecting multiple elements.
userEvent.hover moves cursor to element
userEvent.hover(element: Element | Locator, options?: UserEventHoverOptions): Promise<void> moves the cursor position to the selected element. Can be called on userEvent or directly on a locator. With webdriverio provider, the cursor moves to the center of the element by default. With playwright provider, the cursor moves to "some" visible point of the element.
userEvent.unhover moves cursor to document.body
userEvent.unhover(element: Element | Locator, options?: UserEventHoverOptions): Promise<void> works the same as userEvent.hover but moves the cursor to document.body instead. By default, cursor position is in "some" visible place (playwright provider) or center (webdriverio provider) of the body element, so if the currently hovered element is already in the same position, this method will have no effect. Can be called on userEvent or directly on a locator.
userEvent.upload changes file input element files
userEvent.upload(element: Element | Locator, files: string[] | string | File[] | File, options?: UserEventUploadOptions): Promise<void> changes a file input element to have the specified files. Files can be File objects or file paths relative to the project root. Can be called on userEvent or directly on a locator. WebdriverIO provider only supports this in chrome and edge browsers and only supports string types.
userEvent.dragAndDrop drags source element to target
userEvent.dragAndDrop(source: Element | Locator, target: Element | Locator, options?: UserEventDragAndDropOptions): Promise<void> drags the source element on top of the target element. The source element must have the draggable attribute set to true. Can be called on userEvent or use locator.dropTo(target). Not supported by the default preview provider.
userEvent.copy copies selected text to clipboard
userEvent.copy(): Promise<void> copies the selected text to the clipboard.
userEvent.cut cuts selected text to clipboard
userEvent.cut(): Promise<void> cuts the selected text to the clipboard.
userEvent.paste pastes text from clipboard
userEvent.paste(): Promise<void> pastes text from the clipboard.
userEvent methods accept provider options
Almost every userEvent method inherits its provider options, allowing you to pass browser provider-specific configuration to control behavior.