Cursor Tab: get multi-line edits right and verify them
Cursor Tab is the editor’s built-in completion model: it predicts the next edit near the cursor, including multi-line changes and jumps to the next place that needs a related change, and the Tab key accepts it. Tab is most reliable when the pattern to continue is already visible, and accepted code still needs a type, lint or test gate.
You press Tab, get a plausible 12-line handler, and accept it. Two days later a reviewer finds that it returns "User not found" from the posts endpoint, because Tab copied the pattern faithfully and the one detail that mattered came along with it. Speed was never the problem; knowing which suggestions to trust, and catching the ones you should not have trusted, is.
This page is for developers who still type code in Cursor’s editor and want Tab to carry the mechanical part of it. Feature-sized work belongs to Cursor’s agent; Tab is for the edits you would otherwise type yourself.
What you’ll walk away with from these Tab tips
Section titled “What you’ll walk away with from these Tab tips”- A working model of what Tab predicts, and what that means for where you put your cursor and which files you edit first.
- A two-example seeding technique and an intent-comment recipe that make the first suggestion the right one more often.
- Three copy-paste prompts that hand off from Tab to inline edit and Agent: one to rewrite a scaffold, one to check a Tab-written batch, one to prove Tab-written tests can fail.
- A set of cheap gates (exhaustiveness checks,
satisfies, watch-mode tests) that catch a wrong suggestion without you rereading every accepted line. - A failure-mode table for the ways Tab goes wrong, with the recovery for each.
How does Cursor Tab decide what to suggest?
Section titled “How does Cursor Tab decide what to suggest?”Tab works from what is near the cursor and from your last edit. The subsections below explain what it predicts, how to put the pattern in its view, and which jobs it suits.
Tab predicts the next edit, not the next word
Section titled “Tab predicts the next edit, not the next word”A classic autocomplete finishes the token you are typing. Cursor Tab proposes an edit: it can rewrite several lines around the cursor, and after you accept one change it can offer a jump to the next location that needs a related change. In practice that means one accepted suggestion is often the first of a short sequence:
- You rename a parameter; Tab offers the same rename at the next usage.
- You add a field to one object literal; Tab offers it in the sibling literal below.
- You add a call to a new helper; Tab offers the import it needs.
Treat each Tab press as accepting one step of a sequence, and check each step as you go. A chain of ten accepted edits is ten decisions, not one.
Put the pattern where Tab can see it
Section titled “Put the pattern where Tab can see it”Tab predicts from the code around the cursor and from the edit you made last. The practical rule follows: make the pattern visible before you ask Tab to continue it. Before you write a new endpoint, make sure the closest existing one sits in the same file, ideally directly above where the new code goes, or make the first change by hand so Tab has an edit to continue. A suggestion that ignores your conventions usually means the example it needed was not near the cursor.
For deliberate context selection with the agent (@-mentions, rules, indexing), see context management in Cursor. Tab has no prompt box for @-mentions (Cursor 3.x line, as of 2026-09-26); you steer it with the code you place near the cursor.
Use Tab for more of the same, not for something new
Section titled “Use Tab for more of the same, not for something new”Tab’s strength is continuation. When the next edit is a variation of something already on screen, it is the fastest surface Cursor has. When the next edit needs a decision that is not visible anywhere, use a surface that takes an instruction.
| The next edit is… | Use | Why |
|---|---|---|
| The fourth instance of a pattern with three on screen | Tab | The pattern is visible, so the suggestion is mostly right |
| A change to one selected block (“add retry with backoff”) | Inline edit | You need to state an instruction the code does not contain |
| A change across files, or one that needs running tests | Agent | It can read, edit and run commands, then report evidence |
| Business logic nobody has written yet | Agent with a spec, or you | Tab can only guess at rules it has never seen |
Accept, partially accept or reject a Tab suggestion
Section titled “Accept, partially accept or reject a Tab suggestion”Every suggestion is a choice to take all of it, part of it or none of it. The subsections below cover the keys, what to check before you accept, and how to chain accepted edits through a repetitive change.
Take only the part of a suggestion that is right
Section titled “Take only the part of a suggestion that is right”You do not have to take a suggestion whole:
Tabaccepts the whole suggestion.- Partial accept takes it word by word. The last reported default is
Cmd+Right Arrowon macOS (Ctrl+Right Arrowon Windows and Linux) as of 2026-09-26; confirm it by searching the Keyboard Shortcuts editor for “partial”, and see the keyboard shortcuts reference. Escapedismisses the suggestion.
Partial accept pays off when the structure is right and a value is wrong: take the call and the first arguments, then type the argument Tab got wrong.
Judge each suggestion by the detail most likely to be wrong
Section titled “Judge each suggestion by the detail most likely to be wrong”A suggestion that copies a pattern is rarely wrong in its shape. It is wrong in the one place the new case differs: the entity name, the status code, the error message, the fixture ID. Look there first, decide, and move on: accept with Tab or dismiss with Escape. Typing over a half-accepted suggestion leaves you with a merge of your intent and Tab’s, which is the hardest version to check later.
Chain Tab through a repetitive change
Section titled “Chain Tab through a repetitive change”For a change that repeats down a file (a new field on every fixture, a renamed option in every call), let Tab walk it:
- Make the first change by hand, exactly as you want every instance to look.
- Press Tab when the next suggestion appears, or when Tab offers a jump to the next location.
- Check the one detail that varies per instance before each press.
- Stop the chain the moment a suggestion is wrong; fix that instance by hand, and Tab continues from your corrected edit.
- Run the file’s tests or the type checker once the chain ends.
Seed Tab so the first suggestion is right
Section titled “Seed Tab so the first suggestion is right”Three habits make Tab’s first suggestion the one you want: examples, an intent comment and descriptive names.
Write two examples, let Tab write the third
Section titled “Write two examples, let Tab write the third”The most dependable Tab workflow: write two instances of a pattern by hand, then put the cursor where the third starts. Two examples show Tab both what stays constant and what varies.
// Written by hand:it("returns 200 for an existing user", async () => { const res = await request(app).get("/api/users/1"); expect(res.status).toBe(200); expect(res.body).toHaveProperty("id");});
it("returns 404 for a missing user", async () => { const res = await request(app).get("/api/users/999"); expect(res.status).toBe(404); expect(res.body.error).toBe("User not found");});
// Type `it(` here. Tab typically proposes the next case in the same shape,// for example a 400 for a non-numeric ID. Check the status and the message.Write the intent as a comment before the code
Section titled “Write the intent as a comment before the code”A comment above an empty line gives Tab the one thing the surrounding code cannot: what you intend to do next. The comment works best when it names both the condition and the exact response.
Delete or keep the comment afterwards on its merits; a comment that restates the next line adds nothing to the file.
Name variables for what they hold
Section titled “Name variables for what they hold”Tab reads your identifiers. const data = await fetch(url) tells it nothing about what comes next; const userProfileResponse = await fetch(`/api/users/${userId}/profile`) tells it the resource, the ID and that the next lines probably check the response and parse a profile. Descriptive names cost nothing and remove guesswork from every suggestion that follows.
Where Tab does its best work, and the gate that checks it
Section titled “Where Tab does its best work, and the gate that checks it”Each of the patterns below is one where Tab is usually right, paired with a check that catches it when it is not. The gate matters more than the pattern: it is what lets you accept quickly.
Switch statements, checked for exhaustiveness
Section titled “Switch statements, checked for exhaustiveness”Write the first case by hand and Tab proposes the rest from the union type. Add an exhaustiveness check so a missing or misspelled case is a compile error instead of something you have to spot:
type Status = "pending" | "active" | "suspended" | "deleted";
function statusLabel(status: Status): string { switch (status) { case "pending": return "Pending review"; // Tab proposes "active", "suspended" and "deleted" in the same shape. default: { const unhandled: never = status; throw new Error(`Unhandled status: ${unhandled}`); } }}If Tab skips a member of the union, status is not never in the default branch and the type checker fails. Adding a new status later fails the build in the same way.
Configuration objects, checked with satisfies
Section titled “Configuration objects, checked with satisfies”Tab fills configuration objects well once it has seen two or three properties. It also fills them with plausible values that are not yours. Anchor the object to its type so an invented or misspelled key fails:
const dbConfig = { host: "localhost", port: 5432, // Tab proposes database, user, pool size and so on from the type and nearby code.} satisfies DatabaseConfig;satisfies rejects a property the type does not declare, and a missing required one, while keeping the literal types. What it cannot catch is a wrong value of the right type, such as a pool size copied from another service. Environment-dependent values belong in environment variables, not in whatever Tab saw last.
Test cases, then prove the tests can fail
Section titled “Test cases, then prove the tests can fail”With the implementation open in the editor, start a describe block in the test file, write one case by hand and let Tab propose the next ones. Tab-written tests have a specific failure mode: they can assert what the code does rather than what it should do, so they pass against a bug. Prove they can fail before you trust them.
A mutation that no test catches is a test you still need to write, and that is a better use of your attention than rereading the tests Tab wrote. For the full test-first loop in Cursor, see test-driven development in Cursor.
Hand off from Tab to inline edit and Agent
Section titled “Hand off from Tab to inline edit and Agent”Tab stops being the right tool once a change needs a rule the code does not contain, a check across many accepted lines, or no suggestions at all. The subsections below cover each handoff.
Scaffold with Tab, then rewrite the core with inline edit
Section titled “Scaffold with Tab, then rewrite the core with inline edit”Tab is fast at the parts that repeat: signature, validation shape, error handling, return type. It cannot know a business rule that appears nowhere in the code. Let Tab produce the scaffold, then select the body and state the rule with inline edit (Cmd+K on macOS, Ctrl+K on Windows and Linux by default; confirm in the keyboard shortcuts reference).
After the inline edit lands, Tab picks up again from the new code: it tends to offer the matching test cases or call-site changes next, and the same gates apply to those.
Check a Tab-written batch without reading every line
Section titled “Check a Tab-written batch without reading every line”Accepting Tab suggestions for an hour produces a diff in which every line looked plausible at the moment you accepted it. Rereading all of it is the slow path. Use gates for the structure and point your attention, or an agent’s, at the details copied patterns get wrong.
- Keep the type checker and the test runner in watch mode while you work (
npx tsc --noEmit --watchandnpx vitest, or your stack’s equivalents). A wrong Tab suggestion that breaks a type or a test shows up seconds after you accept it, not in CI. - Let lint run on save. Unused imports, shadowed variables and unreachable code are typical leftovers of a chain that went one step too far.
- Before you commit, ask Agent for a targeted check of the details that pattern-copying gets wrong, using the prompt below. It reads the diff so you read only its findings.
- You sign off at the commit. Tab never commits, and the accept key is not a review. The commit is where you decide, on the evidence from steps 1–3, that the batch is yours.
For the wider practice of trusting evidence over line-by-line reading, see reading evidence instead of code.
Turn Tab off where it costs more than it saves
Section titled “Turn Tab off where it costs more than it saves”Tab suggestions in prose, large data files or a hand-written algorithm you are reasoning through can cost more attention than they save. Cursor Tab is Cursor’s own model, not VS Code’s IntelliSense, so it is configured in Cursor Settings, not through VS Code’s editor.suggest.* settings.
In earlier 3.x builds the Cursor Tab status-bar item offered snooze and per-extension disable (for file types such as md or json), and Cursor Settings had a Tab section. These controls were not re-checked on 2026-09-26, so search Cursor Settings for “Tab” to find them in your build.
If your build has them, snooze suits a focused hour of non-code work, and a per-extension disable suits a file type that is consistently noisy.
When Tab suggestions go wrong
Section titled “When Tab suggestions go wrong”| Symptom | Likely cause | Recovery |
|---|---|---|
| The suggestion has the right shape and a wrong value (status code, message, name) | Tab copied the nearest example, including the detail that should have changed | Partial-accept the structure and type the value; run the diff-review prompt above before committing |
| Tab keeps proposing the old pattern after a migration (class components, a deprecated client) | The old pattern is what sits near the cursor | Migrate one or two instances by hand first, in the same file or directly above; Tab continues from recent edits |
| Tab imports a symbol from the wrong package | Several packages export the same name | Dismiss, write the correct import once at the top of the file, then continue; the type checker catches the wrong one if you accepted it |
| Tab-written tests all pass, including against a known bug | The tests assert current behaviour, not intended behaviour | Run the mutation prompt above; add the cases it shows are missing |
| Tab proposes a real-looking URL, key or hostname | It continued a literal it saw elsewhere in the file | Dismiss it; read the value from configuration or an environment variable. Search the diff for literals before you commit |
| The Tab key does nothing, or inserts a different completion | Another completion extension, such as GitHub Copilot, is bound to the same key, or Tab is snoozed | Check whether Tab is snoozed or disabled (search Cursor Settings for “Tab”); disable the other extension’s inline suggestions for this workspace |
| A long chain drifted and you are not sure which edits were right | Several accepted steps compounded one early mistake | Stop, run the type checker and tests, and undo back to the last green state instead of patching forward |
Where to go next with Cursor editing
Section titled “Where to go next with Cursor editing”- Before this page: Cursor core features, for choosing between Tab, inline edit and Agent.
- Next: Cursor inline edit, for instructions applied to a selection, which is the natural partner to Tab’s continuation.
- Then: agent chat workflows in Cursor, for changes that span files and need commands run.
- For the gates themselves: test-driven development in Cursor.
- For where Tab sits in the bigger picture: levels 1–2 of the autonomy ladder, assisted and paired coding.