Skip to main content
Cypress App

closest

Get the first DOM element that matches the selector (whether it be itself or one of its ancestors).

.closest() tests the element itself first, then travels up the DOM tree through its ancestors.

info

The querying behavior of this command matches how .closest() works in jQuery, except that Cypress continues past shadow DOM boundaries. See Shadow DOM boundaries and .closest().

Syntax​

.closest(selector)
.closest(selector, options)

Usage​

Correct Usage

cy.get('td').closest('.filled') // Yield closest el with class 'filled'

Incorrect Usage

cy.closest('.active') // Errors, cannot be chained off 'cy'
cy.clock().closest() // Errors, 'clock' does not yield DOM elements

Arguments​

selector (String selector)

A selector the element itself or one of its ancestors must match.

options (Object)

Pass in an options object to change the default behavior of .closest().

OptionDefaultDescription
logtrueDisplays the command in the Command log
timeoutdefaultCommandTimeoutTime to wait for .closest() to resolve before timing out

Yields ​

  • .closest() yields the new DOM element(s) it found. When the subject holds more than one element, it yields the closest match for each one, with duplicates removed.
  • .closest() is a query, and it is safe to chain further commands.

Examples​

Selector​

Find the closest ancestor of p.error with class banner​

<div class="banner">
<div class="content">
<p class="error">Payment failed</p>
</div>
</div>
// yields <div class="banner">…</div>
cy.get('p.error').closest('.banner')

Yield the subject itself when it matches​

<ul class="nav">
<li class="active">Home</li>
</ul>
// yields <li class="active">Home</li>, since the subject
// matches the selector before any ancestor is tested
cy.get('li.active').closest('li')

Act on one card in a repeated list​

Find something unique inside a repeated component, climb to the component with .closest(), then query inside it.

<div data-cy="product-card">
<h3>Trail Runner</h3>
<button>Add to cart</button>
</div>
<div data-cy="product-card">
<h3>Road Racer</h3>
<button>Add to cart</button>
</div>
// clicks the "Add to cart" button in the Road Racer card only
cy.contains('h3', 'Road Racer')
.closest('[data-cy="product-card"]')
.find('button')
.click()

Assert on a form field's wrapper​

Validation state often lives on a wrapper element rather than on the input.

<div class="form-group has-error">
<label for="email">Email</label>
<input id="email" type="email" />
</div>
cy.get('#email').closest('.form-group').should('have.class', 'has-error')

Compare .closest() with .parents()​

.closest() stops at the first match. .parents() collects every matching ancestor.

<section class="panel outer">
<section class="panel inner">
<button>Save</button>
</section>
</section>
// yields <section class="panel inner">
cy.get('button').closest('.panel')

// yields <section class="panel inner"> and <section class="panel outer">
cy.get('button').parents('.panel')

Assert that an element is not inside a container​

When no ancestor matches, .closest() yields an empty result, so .should('not.exist') passes.

// passes when the checkout button is not inside a modal
cy.get('[data-cy="checkout"]').closest('.modal').should('not.exist')

Notes​

Shadow DOM boundaries and .closest()​

When the subject is inside a shadow root, .closest() crosses the shadow boundary. If nothing inside the shadow root matches, it continues from the shadow host, testing the host itself and then the host's ancestors, until it finds a match or reaches the document. This happens whether or not includeShadowDom is enabled. The option controls whether queries like .find() reach into a shadow root, not whether .closest() climbs back out of one.

<form id="checkout">
<payment-panel>
<template shadowrootmode="open">
<button>Pay now</button>
</template>
</payment-panel>
</form>
// .find() needs includeShadowDom to reach the button;
// .closest() crosses back out of the shadow root on its own
// yields <form id="checkout">
cy.get('payment-panel')
.find('button', { includeShadowDom: true })
.closest('form')

Rules​

Requirements ​

  • .closest() requires being chained off a command that yields DOM element(s) or a document.

Assertions ​

  • .closest() will automatically retry until the element(s) exist in the DOM.
  • .closest() will automatically retry until all chained assertions have passed.

Timeouts ​

  • .closest() can time out waiting for the element(s) to exist in the DOM.
  • .closest() can time out waiting for assertions you've added to pass.

Command Log​

Find the closest element of li.active with the class 'nav'

cy.get('li.active').closest('.nav')

The commands above will display in the Command Log as:

Command Log showing a get entry for li.active followed by a closest entry for .nav

When clicking on the closest command within the command log, the console outputs the following:

Console output for closest, showing the .nav selector applied to li.active and the ul.nav element found

History​

VersionChanges
12.0.0.closest() is now a query. Overwrite it with Cypress.Commands.overwriteQuery() rather than Cypress.Commands.overwrite().

See also​