---
id: api/commands/shadow
title: shadow | Cypress Documentation
description: Traverse into the shadow DOM of an element in Cypress.
section: api
source_path: docs/api/commands/shadow.mdx
version: ce02913654e2655ee63448bdc92bb92c7b46a619
updated_at: '2026-04-22T19:37:51.587Z'
---
# shadow

Traverse into the shadow DOM of an element.

## Syntax

```javascript
.shadow()
.shadow(options)
```

### Usage

 **Correct Usage**

```javascript
cy.get('.shadow-host').shadow()
```

 **Incorrect Usage**

```javascript
cy.shadow() // Errors, cannot be chained off 'cy'
cy.exec('npm start').shadow() // Errors, 'exec' does not yield DOM element
cy.get('.not-a-shadow-host').shadow() // Errors, subject must host a shadow root
```

### Arguments

 **options *(Object)***

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

| Option    | Default                                                                           | Description                                                                                         |
| --------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `log`     | `true`                                                                            | Displays the command in the [Command log](/llm/markdown/app/core-concepts/open-mode.md#Command-Log) |
| `timeout` | [`defaultCommandTimeout`](/llm/markdown/app/references/configuration.md#Timeouts) | Time to wait for `cy.get()` to resolve before [timing out](#Timeouts)                               |

### Yields [Learn about subject management](/llm/markdown/app/core-concepts/introduction-to-cypress.md#Subject-Management)

- `.shadow()` yields the new DOM element(s) it found.
- `.shadow()` is a query, and it is *safe* to chain further commands.

## Examples

### Find and click on a button inside the shadow DOM

```html
<div class="shadow-host">
  #shadow-root
  <button class="my-button">Click me</button>
</div>
```

```javascript
// yields [#shadow-root (open)]
cy.get('.shadow-host').shadow().find('.my-button').click()
```

## Rules

### Requirements [Learn about chaining commands](/llm/markdown/app/core-concepts/introduction-to-cypress.md#Chains-of-Commands)

- `.shadow()` requires being chained off a command that yields a DOM element
  that is a shadow host (i.e. has a shadow root directly attached to it).

### Assertions [Learn about assertions](/llm/markdown/app/core-concepts/introduction-to-cypress.md#Assertions)

- `.shadow()` will automatically [retry](/llm/markdown/app/core-concepts/retry-ability.md)
  until the element(s)
  [exist in the DOM](/llm/markdown/app/core-concepts/introduction-to-cypress.md#Implicit-Assertions).
- `.shadow()` will automatically [retry](/llm/markdown/app/core-concepts/retry-ability.md)
  until the element(s) host(s) a shadow root.
- `.shadow()` will automatically [retry](/llm/markdown/app/core-concepts/retry-ability.md)
  until all chained assertions have passed.

### Timeouts [Learn about timeouts](/llm/markdown/app/core-concepts/introduction-to-cypress.md#Timeouts)

- `.shadow()` can time out waiting for the element(s) to
  [exist in the DOM](/llm/markdown/app/core-concepts/introduction-to-cypress.md#Implicit-Assertions).
- `.shadow()` can time out waiting for the element(s) to host a shadow root.
- `.shadow()` can time out waiting for assertions you've added to pass.

## Known Issue

When working with `cy.click()`, it sometimes won't click the right element in
Chrome. It's happening because of
[the ambiguity in spec](https://bugs.chromium.org/p/chromium/issues/detail?id=1188919\&q=shadowRoot%20elementFromPoint\&can=2).

In this case, pass `'top'` to `cy.click()` like below:

```js
cy.get('#element').shadow().find('[data-test-id="my-button"]').click('top')
```

## Command Log

***Traverse into the shadow DOM of an element***

```javascript
cy.get('.shadow-host').shadow()
```

The commands above will display in the Command Log as:

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

## See also

- [`cy.get()`](/llm/markdown/api/commands/get.md#Arguments) with `includeShadowDom` option
- [`cy.find()`](/llm/markdown/api/commands/find.md#Arguments) with `includeShadowDom` option
- [`cy.contains()`](/llm/markdown/api/commands/contains.md#Arguments) with `includeShadowDom`
  option
- [`includeShadowDom` config option](/llm/markdown/app/references/configuration.md#Global)
