---
title: Locators | Browser Mode
outline: [2, 3]
---
# Locators 2.1.0
A locator is a representation of an element or a number of elements. Every locator is defined by a string called a selector. Vitest abstracts this selector by providing convenient methods that generate those selectors behind the scenes.
The locator API uses a fork of [Playwright's locators](https://playwright.dev/docs/api/class-locator) called [Ivya](https://npmjs.com/ivya). However, Vitest provides this API to every [provider](/guide/browser/#provider-configuration).
## getByRole
- **Type:** `(role: ARIARole | string, options?: LocatorByRoleOptions) => Locator`
Creates a way to locate an element by its [ARIA role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles), [ARIA attributes](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes) and [accessible name](https://developer.mozilla.org/en-US/docs/Glossary/Accessible_name).
::: tip
If you only query for a single element with `getByText('The name')` it's oftentimes better to use `getByRole(expectedRole, { name: 'The name' })`. The accessible name query does not replace other queries such as `*ByAltText` or `*ByTitle`. While the accessible name can be equal to these attributes, it does not replace the functionality of these attributes.
:::
Consider the following DOM structure.
```html
Sign up
```
You can locate each element by its implicit role:
```ts
await expect.element(
page.getByRole('heading', { name: 'Sign up' })
).toBeVisible()
await page.getByRole('textbox', { name: 'Login' }).fill('admin')
await page.getByRole('textbox', { name: 'Password' }).fill('admin')
await page.getByRole('button', { name: /submit/i }).click()
```
::: warning
Roles are matched by string equality, without inheriting from the ARIA role hierarchy. As a result, querying a superclass role like `checkbox` will not include elements with a subclass role like `switch`.
By default, many semantic elements in HTML have a role; for example, `` has the "radio" role. Non-semantic elements in HTML do not have a role; `
` and `` without added semantics return `null`. The `role` attribute can provide semantics.
Providing roles via `role` or `aria-*` attributes to built-in elements that already have an implicit role is **highly discouraged** by ARIA guidelines.
:::
##### Options
- `exact: boolean`
Whether the `name` is matched exactly: case-sensetive and whole-string. Disabled by default. This option is ignored if `name` is a regular expression. Note that exact match still trims whitespace.
```tsx
page.getByRole('button', { name: 'hello world' }) // ✅
page.getByRole('button', { name: 'hello world', exact: true }) // ❌
page.getByRole('button', { name: 'Hello World', exact: true }) // ✅
```
- `checked: boolean`
Should checked elements (set by `aria-checked` or ``) be included or not. By default, the filter is not applied.
See [`aria-checked`](https://www.w3.org/TR/wai-aria-1.2/#aria-checked) for more information
```tsx
<>
>
page.getByRole('checkbox', { checked: true }) // ✅
page.getByRole('checkbox', { checked: false }) // ❌
```
- `disabled: boolean`
Should disabled elements be included or not. By default, the filter is not applied. Note that unlike other attributes, `disable` state is inherited.
See [`aria-disabled`](https://www.w3.org/TR/wai-aria-1.2/#aria-disabled) for more information
```tsx
page.getByRole('textbox', { disabled: true }) // ✅
page.getByRole('textbox', { disabled: false }) // ❌
```
- `expanded: boolean`
Should expanded elements be included or not. By default, the filter is not applied.
See [`aria-expanded`](https://www.w3.org/TR/wai-aria-1.2/#aria-expanded) for more information
```tsx
Link
page.getByRole('link', { expanded: true }) // ✅
page.getByRole('link', { expanded: false }) // ❌
```
- `includeHidden: boolean`
Should elements that are [normally excluded](https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion) from the accessibility tree be queried. By default, only non-hidden elements are matched by role selector.
Note that roles `none` and `presentation` are always included.
```tsx
page.getByRole('button') // ❌
page.getByRole('button', { includeHidden: false }) // ❌
page.getByRole('button', { includeHidden: true }) // ✅
```
- `level: number`
A number attribute that is usually present for `heading`, `listitem`, `row`, `treeitem` roles with default values for `
-
` elements. By default, the filter is not applied.
See [`aria-level`](https://www.w3.org/TR/wai-aria-1.2/#aria-level) for more information
```tsx
<>
Heading Level One
Second Heading Level One
>
page.getByRole('heading', { level: 1 }) // ✅
page.getByRole('heading', { level: 2 }) // ❌
```
- `name: string | RegExp`
[An accessible name](https://developer.mozilla.org/en-US/docs/Glossary/Accessible_name). By default, matching is case-insensitive and searches for a substring. Use `exact` option to control this behavior.
```tsx
page.getByRole('button', { name: 'Click Me!' }) // ✅
page.getByRole('button', { name: 'click me!' }) // ✅
page.getByRole('button', { name: 'Click Me?' }) // ❌
```
- `pressed: boolean`
Should pressed elements be included or not. By default, the filter is not applied.
See [`aria-pressed`](https://www.w3.org/TR/wai-aria-1.2/#aria-pressed) for more information
```tsx
page.getByRole('button', { pressed: true }) // ✅
page.getByRole('button', { pressed: false }) // ❌
```
- `selected: boolean`
Should selected elements be included or not. By default, the filter is not applied.
See [`aria-selected`](https://www.w3.org/TR/wai-aria-1.2/#aria-selected) for more information
```tsx
page.getByRole('button', { selected: true }) // ✅
page.getByRole('button', { selected: false }) // ❌
```
##### See also
- [List of ARIA roles at MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles)
- [List of ARIA roles at w3.org](https://www.w3.org/TR/wai-aria-1.2/#role_definitions)
- [testing-library's `ByRole`](https://testing-library.com/docs/queries/byrole/)
## getByAltText
- **Type:** `(text: string | RegExp, options?: LocatorOptions) => Locator`
Creates a locator capable of finding an element with an `alt` attribute that matches the text. Unlike testing-library's implementation, Vitest will match any element that has a matching `alt` attribute.
```tsx
page.getByAltText(/incredibles.*? poster/i) // ✅
page.getByAltText('non existing alt text') // ❌
```
#### Options
- `exact: boolean`
Whether the `text` is matched exactly: case-sensetive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
#### See also
- [testing-library's `ByAltText`](https://testing-library.com/docs/queries/byalttext/)
## getByLabelText
- **Type:** `(text: string | RegExp, options?: LocatorOptions) => Locator`
Creates a locator capable of finding an element that has an assosiated label.
The `page.getByLabelText('Username')` locator will find every input in the example bellow:
```html
// for/htmlFor relationship between label and form element id
// The aria-labelledby attribute with form elements
// Wrapper labels
// Wrapper labels where the label text is in another child element
// aria-label attributes
// Take care because this is not a label that users can see on the page,
// so the purpose of your input must be obvious to visual users.
```
#### Options
- `exact: boolean`
Whether the `text` is matched exactly: case-sensetive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
#### See also
- [testing-library's `ByLabelText`](https://testing-library.com/docs/queries/bylabeltext/)
## getByPlaceholder
- **Type:** `(text: string | RegExp, options?: LocatorOptions) => Locator`
Creates a locator capable of finding an element that has the specified `placeholder` attribute. Vitest will match any element that has a matching `placeholder` attribute, not just `input`.
```tsx
page.getByPlaceholder('Username') // ✅
page.getByPlaceholder('not found') // ❌
```
::: warning
It is generally better to rely on a label using [`getByLabelText`](#getbylabeltext) than a placeholder.
:::
#### Options
- `exact: boolean`
Whether the `text` is matched exactly: case-sensetive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
#### See also
- [testing-library's `ByPlaceholderText`](https://testing-library.com/docs/queries/byplaceholdertext/)
## getByText
- **Type:** `(text: string | RegExp, options?: LocatorOptions) => Locator`
Creates a locator capable of finding an element that contains the specified text. The text will be matched against TextNode's [`nodeValue`](https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeValue) or input's value if the type is `button` or `reset`. Matching by text always normalizes whitespace, even with exact match. For example, it turns multiple spaces into one, turns line breaks into spaces and ignores leading and trailing whitespace.
```tsx
About ℹ️
page.getByText(/about/i) // ✅
page.getByText('about', { exact: true }) // ❌
```
::: tip
This locator is useful for locating non-interactive elements. If you need to locate an interactive element, like a button or an input, prefer [`getByRole`](#getbyrole).
:::
#### Options
- `exact: boolean`
Whether the `text` is matched exactly: case-sensetive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
#### See also
- [testing-library's `ByText`](https://testing-library.com/docs/queries/bytext/)
## getByTitle
- **Type:** `(text: string | RegExp, options?: LocatorOptions) => Locator`
Creates a locator capable of finding an element that has the specified `title` attribute. Unlike testing-library's `getByTitle`, Vitest cannot find `title` elements within an SVG.
```tsx
page.getByTitle('Delete') // ✅
page.getByTitle('Create') // ❌
```
#### Options
- `exact: boolean`
Whether the `text` is matched exactly: case-sensetive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
#### See also
- [testing-library's `ByTitle`](https://testing-library.com/docs/queries/bytitle/)
## getByTestId
- **Type:** `(text: string | RegExp) => Locator`
Creates a locator capable of finding an element that matches the specified test id attribute. You can configure the attribute name with [`browser.locators.testIdAttribute`](/config/#browser-locators-testidattribute).
```tsx
page.getByTestId('custom-element') // ✅
page.getByTestId('non-existing-element') // ❌
```
::: warning
It is recommended to use this only after the other locators don't work for your use case. Using `data-testid` attributes does not resemble how your software is used and should be avoided if possible.
:::
#### Options
- `exact: boolean`
Whether the `text` is matched exactly: case-sensetive and whole-string. Disabled by default. This option is ignored if `text` is a regular expression. Note that exact match still trims whitespace.
#### See also
- [testing-library's `ByTestId`](https://testing-library.com/docs/queries/bytestid/)
## Methods
### click
- **Type:** `(options?: UserEventClickOptions) => Promise`
Click on an element. You can use the options to set the cursor position.
```ts
import { page } from '@vitest/browser/context'
await page.getByRole('img', { name: 'Rose' }).click()
```
- [See more at `userEvent.click`](/guide/browser/interactivity-api#userevent-click)
### dblClick
- **Type:** `(options?: UserEventClickOptions) => Promise`
Triggers a double click event on an element. You can use the options to set the cursor position.
```ts
import { page } from '@vitest/browser/context'
await page.getByRole('img', { name: 'Rose' }).dblClick()
```
- [See more at `userEvent.dblClick`](/guide/browser/interactivity-api#userevent-dblclick)
### tripleClick
- **Type:** `(options?: UserEventClickOptions) => Promise`
Triggers a triple click event on an element. Since there is no `tripleclick` in browser api, this method will fire three click events in a row.
```ts
import { page } from '@vitest/browser/context'
await page.getByRole('img', { name: 'Rose' }).tripleClick()
```
- [See more at `userEvent.tripleClick`](/guide/browser/interactivity-api#userevent-tripleclick)
### clear
- **Type:** `() => Promise`
Clears the input element content.
```ts
import { page } from '@vitest/browser/context'
await page.getByRole('textbox', { name: 'Full Name' }).clear()
```
- [See more at `userEvent.clear`](/guide/browser/interactivity-api#userevent-clear)
### hover
- **Type:** `(options?: UserEventHoverOptions) => Promise`
Moves the cursor position to the selected element.
```ts
import { page } from '@vitest/browser/context'
await page.getByRole('img', { name: 'Rose' }).hover()
```
- [See more at `userEvent.hover`](/guide/browser/interactivity-api#userevent-hover)
### unhover
- **Type:** `(options?: UserEventHoverOptions) => Promise`
This works the same as [`locator.hover`](#hover), but moves the cursor to the `document.body` element instead.
```ts
import { page } from '@vitest/browser/context'
await page.getByRole('img', { name: 'Rose' }).unhover()
```
- [See more at `userEvent.unhover`](/guide/browser/interactivity-api#userevent-unhover)
### fill
- **Type:** `(text: string, options?: UserEventFillOptions) => Promise`
Sets the value of the current `input`, `textarea` or `conteneditable` element.
```ts
import { page } from '@vitest/browser/context'
await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean')
```
- [See more at `userEvent.fill`](/guide/browser/interactivity-api#userevent-fill)
### dropTo
- **Type:** `(target: Locator, options?: UserEventDragAndDropOptions) => Promise`
Drags the current element to the target location.
```ts
import { page } from '@vitest/browser/context'
const paris = page.getByText('Paris')
const france = page.getByText('France')
await paris.dropTo(france)
```
- [See more at `userEvent.dragAndDrop`](/guide/browser/interactivity-api#userevent-draganddrop)
### selectOptions
- **Type:** `(values: HTMLElement | HTMLElement[] | string | string[], options?: UserEventSelectOptions) => Promise`
Choose one or more values from a `