In Playwright, what does locator.press('Control+Enter') send to the page, and how are key names resolved?
answer
- The element is focused first
- A key name, not typed text
- Plus sign holds the modifier down
- One string for Control and Meta
- delay separates keydown from keyup
basics
~10 slocator.press focuses the matched element, holds Control, presses and releases Enter, then releases Control. The argument is one logical key name or a single character, with modifiers joined by plus signs.
solid answer
~40 s`locator.press(key)` focuses the element the locator resolves to and then sends one `keydown` and one `keyup` through the browser's real input pipeline. The argument is a key string, not text: Playwright accepts the logical `KeyboardEvent.key` names -- `Enter`, `Escape`, `Tab`, `ArrowRight`, `F1`-`F12`, `Digit0`-`Digit9`, `KeyA`-`KeyZ` -- or a single character such as `a` or `#`, which is case-sensitive. A plus sign builds a chord: in `Control+Enter` the modifier is pressed and held while `Enter` is pressed, then released. `Shift`, `Control`, `Alt`, `Meta` and `ControlOrMeta` are the available modifiers, and `ControlOrMeta` resolves to `Control` on Windows and Linux and to `Meta` on macOS, so one string covers both. The `delay` option waits between the `keydown` and the `keyup`.
code
typescript · 9 lines// Issue tracker: post a comment with the composer's Ctrl/Cmd+Enter shortcut.
const composer = page.getByRole('textbox', { name: 'Add a comment' });
await composer.press('ControlOrMeta+Enter');
await expect(page.getByText('Comment posted')).toBeVisible();
// A named key, and a case-sensitive single character.
const search = page.getByRole('searchbox', { name: 'Search issues' });
await search.press('Escape');
await search.press('/');go deeper
Remember that press takes one key name or one character, never a sentence, and that Playwright focuses the element for you. Learn Enter, Escape, Tab and the arrow keys by their names.
Explain that a plus sign holds the modifier down across the key that follows, that ControlOrMeta resolves per operating system, and that delay sits between the keydown and the keyup rather than around the call.
Show judgment about shortcut tests: assert the resulting state rather than the keystroke, and know how to tell a swallowed key from a focus problem when the shortcut silently does nothing.
Own the cross-platform policy. Mandate ControlOrMeta so nobody hard-codes a macOS-only chord, and decide whether shortcut coverage is worth running on every operating system your team actually ships to.
## The verb and what it sends `locator.press(key)` is Playwright's single-keystroke action. It resolves the locator to one element, **focuses that element**, and then produces exactly one `keydown` followed by one `keyup` through the browser's real input pipeline -- the same path `page.keyboard.down()` and `page.keyboard.up()` take. Because the focus step is built in, you do not have to click the field first: the keystroke lands on the element the locator named, and the page's own handlers see events indistinguishable from a user's. The argument is a **key string, not text**. `press('Enter')` sends the Enter key; it does not type the five letters `E`, `n`, `t`, `e`, `r`. Getting that distinction right is the whole of the beginner's version of this question, and it is what separates `press` from the verbs that put a value into a field. ## Key names, characters and case Playwright reads the string as the logical `KeyboardEvent.key` value the page will observe. The named keys include: - navigation and editing: `Enter`, `Escape`, `Tab`, `Backspace`, `Delete`, `Insert`, `Home`, `End`, `PageUp`, `PageDown` - arrows: `ArrowUp`, `ArrowDown`, `ArrowLeft`, `ArrowRight` - ranges: `F1`-`F12`, `Digit0`-`Digit9`, `KeyA`-`KeyZ` - punctuation names: `Backquote`, `Minus`, `Equal`, `Backslash` Alternatively you give a **single character** to generate -- `a`, `#`, `/`, `$`. Single characters are case-sensitive: `press('a')` and `press('A')` are different keystrokes producing different text. An issue tracker whose "focus search" shortcut is the slash key is therefore driven with `press('/')`, not with an invented name like `Slash`. ## Chords: the plus sign is a hold A `+` in the string builds a chord. In `Control+Enter` the modifier is pressed and held while `Enter` is pressed and released, and only then is the modifier released. The modifiers accepted here are `Shift`, `Control`, `Alt`, `Meta` and `ControlOrMeta`, and they stack: `Control+Shift+T` is a valid string. Holding `Shift` also makes a character key produce its upper-case text, which is why `press('Shift+A')` puts a capital `A` into a field. `ControlOrMeta` is the cross-platform escape from a real maintenance problem. A web app usually binds its submit shortcut to Cmd on macOS and Ctrl everywhere else, so a hard-coded `Meta+Enter` passes on a laptop and fails on a Linux runner. Playwright resolves `ControlOrMeta` to `Control` on Windows and Linux and to `Meta` on macOS, so one string covers both without branching on the platform in test code. | you write | what the page receives | |---|---| | `press('Enter')` | `keydown` and `keyup` with `key` of `Enter` | | `press('a')` | `keydown` and `keyup` with `key` of `a`, text `a` | | `press('A')` | `keydown` and `keyup` with `key` of `A`, text `A` | | `press('Control+Enter')` | `Control` down, `Enter` down and up, `Control` up | | `press('$')` | the `$` character, no named key involved | ## The option that reshapes the keystroke `delay` waits that many milliseconds between the `keydown` and the `keyup` of the key, and defaults to `0`. It matters for pages that treat a long press differently from a tap, or that debounce on how long a key was held. Everything else you can pass is shared with the rest of the action verbs and is not specific to keyboard input. ## Where press sits among the keyboard surfaces 1. `locator.press(key)` -- one keystroke on a named element, with focus handled for you. This is the default choice, and it is what a shortcut test should use. 2. `page.keyboard.press(key)` -- the same keystroke, but delivered wherever focus already happens to be. Nothing is named and nothing is focused for you. 3. `page.keyboard.down(key)` and `page.keyboard.up(key)` -- hold a key across several later actions and release it explicitly, rather than for the span of one call. Putting a whole value into a field is a different verb altogether and belongs with the form-control actions, not here. ## Reading a shortcut test in practice In the issue tracker, the comment composer posts on `ControlOrMeta+Enter`. The honest test presses the chord on the composer and then asserts the comment appears -- the keystroke is the input, the rendered comment is the observation. If nothing happens, the usual cause is focus: `press` focuses the element the locator matched, but a rich-text composer often keeps focus on an inner `contenteditable` node, so the element you named and the element that receives the key are not the same. Naming the inner editable region, or clicking into the composer first, resolves it. The second-most common cause is a modifier that only exists on one operating system, which is exactly what `ControlOrMeta` was added to remove.
- What does Playwright do differently when the key string is a single character rather than a named key?A single character such as `a`, `#` or `/` is used to generate the text for the keystroke, and it is case-sensitive -- `a` and `A` produce different results. A named key like `ArrowLeft` or `Enter` is matched as the logical `KeyboardEvent.key` value instead and produces no text of its own.
- A keyboard-shortcut test passes on your macOS laptop and fails on the Linux CI machine. What is the likely cause?A hard-coded platform modifier. If the app binds Cmd+Enter on macOS and Ctrl+Enter elsewhere, a fixed `Meta+Enter` string only matches one of them. Use `ControlOrMeta+Enter`, which Playwright resolves to `Meta` on macOS and to `Control` on Windows and Linux, instead of branching on the platform in the test.
- You press Enter on a rich-text composer and nothing happens. Where do you look first?At focus. `press` focuses the element the locator matched, but a rich-text composer often keeps focus on an inner contenteditable node, so the element you named is not the one receiving the key. Name the inner editable region, or click into the composer first, and the keystroke lands.
saying these in an interview costs you the question
- Thinks press types the whole string as text
- Writes ctrl or cmd instead of Control
- Assumes press works without the element being focused
- Hard-codes Meta and expects it to work on Linux
- Believes a and A send the same keystroke