---
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: a8fd16711bdda4c7b5645b9717e588ae99ec2470
updated_at: '2026-05-18T17:21:32.047Z'
---
# shadow

Traverse into the shadow DOM of an element.

## Syntax

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

### Usage

**Correct Usage**

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

**Incorrect Usage**

```
cy.shadow() // Errors, cannot be chained off 'cy'cy.exec('npm start').shadow() // Errors, 'exec' does not yield DOM elementcy.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

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

```
// 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:

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

## Command Log

**_Traverse into the shadow DOM of an element_**

```
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)
