Tab Completion and Code Suggestions
Tab Completion and Code Suggestions
If you have used VS Code's IntelliSense or any other traditional autocomplete, you already have a mental model for how Tab completion works: start typing, see a suggestion, press Tab to accept it. Cursor's Tab completion uses the same key but is doing something fundamentally different underneath. It is not completing a variable name or a method signature -- it is predicting what you are about to write next, sometimes several lines ahead, based on everything it can see in your file and the surrounding code.
This lesson explains how Cursor's Tab completion works, how it differs from traditional autocomplete, and how to build habits that take full advantage of it.
What You'll Learn
- How Cursor's Tab completion generates predictive, multi-line suggestions
- The difference between Tab completion and traditional IDE autocomplete
- How to accept, reject, and partially accept suggestions
- How ghost text appears and what it means
- How Tab uses your surrounding code context to predict intent
- How to toggle Tab completion on and off
- When Tab is most useful: boilerplate, repetitive patterns, and test writing
How Cursor's Tab Completion Works
Traditional autocomplete is lookup-based. The IDE reads your project's type information, imports, and APIs, then offers a list of completions that are syntactically valid at the current position. It is helpful, but it is fundamentally constrained to names and method signatures that already exist.
Cursor's Tab completion is generative. It uses an AI model to look at your file -- what you have written above and below the cursor, the file's overall structure, the code patterns you have established -- and predicts what you are likely to write next. The difference sounds subtle, but in practice it is enormous.
Traditional autocomplete can suggest array.push( after you type array.. Cursor's Tab can generate an entire function body because it has seen the function signature you just wrote and understands the pattern it belongs to.
What Tab Completion Can Generate
- Completing the current line based on context
- Generating the body of a function after you write its signature
- Filling in repetitive patterns (the second item in a list when it sees the first two)
- Writing the next step in a sequence of similar operations
- Suggesting imports after it infers you are using something from a library
- Completing test assertions after seeing the test setup
Ghost Text: Seeing Suggestions Before You Accept Them
When Cursor has a suggestion, it appears as ghost text -- light grey text that shows up after your cursor position. It is called ghost text because it is not part of your file yet. It exists only as a preview.
// You type:
function formatCurrency(amount: number
// Ghost text appears:
function formatCurrency(amount: number, currency: string = 'USD'): string {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency,
}).format(amount);
}
The grey preview shows what will be inserted if you accept it. You can read it and decide whether it is what you want -- or ignore it and keep typing your own code. If you ignore the ghost text and keep typing, it disappears and Cursor generates a new suggestion based on your updated position.
Ghost text is designed to be low-friction. It never interrupts your typing. It appears, you glance at it, and you either accept it with Tab or continue typing. After a few days of using it, scanning the ghost text becomes an unconscious reflex.
Accepting and Rejecting Suggestions
Accepting: Press Tab
When ghost text appears and you want it, press Tab to accept the full suggestion. The entire suggested block replaces the ghost text and becomes real code in your file.
Rejecting: Keep Typing or Press Escape
If you do not want the suggestion, simply keep typing. Your new characters will dismiss the current suggestion and potentially trigger a new one. You can also press Escape to explicitly dismiss the current ghost text.
There is no penalty for rejecting suggestions. Do not feel obligated to accept a suggestion just because it appeared. If it is not right, dismiss it and write what you actually want.
Partial Accepts: Accept Word by Word
Sometimes a multi-line suggestion is mostly right but has one part you want to change. Instead of accepting everything and then deleting what you do not want, you can accept the suggestion one word at a time using Cmd+Right arrow (or Ctrl+Right arrow on Windows/Linux).
Each press of Cmd+Right accepts one more word from the ghost text. This lets you take the useful parts of a long suggestion and stop before the parts that do not fit. It is a precision tool that makes long suggestions more usable.
For example, if the suggestion is a full function body but you only want the first two lines, you can accept those two lines word by word, stop, and write the rest yourself.
How Tab Uses Surrounding Context
The accuracy of Tab's suggestions is directly tied to how much useful context it has. Understanding what it reads helps you understand why some suggestions are excellent and others miss the mark.
Code Above the Cursor
Tab reads everything written above your cursor position in the current file. If you have defined helper functions, types, constants, and imports earlier in the file, Tab understands them and uses them in suggestions. This is why it can suggest a correct return type or use the right variable names -- it has already seen the entire file.
Code Below the Cursor
Cursor also reads code below the cursor. If you are filling in a function body and there is already code after that function, Tab considers it. This bidirectional reading is why it sometimes feels like Tab "knows" what you are working toward.
Established Patterns in the File
If you have written three similar functions in a row, Tab builds a strong expectation of the pattern and suggests the fourth with high accuracy. This is especially valuable for:
- Series of similar route handlers
- Lists of configuration objects
- Multiple similar React components or hooks
- Repeated database query structures
What Tab Does Not Automatically See
Tab's default context is limited to your current file. It does not automatically read types from other files or understand your project's broader architecture unless you are using features like @codebase in the Chat panel. If your suggestion seems to be using wrong types or missing context from another file, that is usually why.
Toggling Tab Completion On and Off
There are situations where Tab's suggestions become a distraction rather than a help. When you are deep in debugging complex logic or writing highly unconventional code, the constant appearance of ghost text can interrupt your thinking.
How to Toggle
You can toggle Tab completion from Cursor's settings:
- Open the Command Palette with Cmd+Shift+P
- Type "Cursor Tab" to find the toggle setting
- Enable or disable as needed
Alternatively, Cursor's status bar at the bottom of the window typically shows the Tab completion status. You can click it to toggle.
When to Turn It Off Temporarily
- When you are writing pseudocode or rough notes inside code comments
- When debugging unusual edge cases where suggestions are consistently wrong
- When pair programming and the ghost text is distracting to your collaborator
Most developers leave Tab enabled almost all the time and learn to ignore suggestions when they are not useful. Turning it off is a tool to have available rather than a regular workflow.
When Tab Completion Is Most Valuable
Tab completion is beneficial across all kinds of coding, but there are particular situations where it saves the most time and reduces the most mental overhead.
Writing Boilerplate
Every codebase has boilerplate that is necessary but mechanical: config objects, component scaffolding, class constructors, module exports. Tab excels here because boilerplate follows predictable patterns that the model has seen many times.
// Type the interface declaration, then Tab completes the rest
interface UserProfile {
id: string;
email: string;
// Tab starts predicting the next fields based on common patterns
displayName: string;
avatarUrl: string | null;
createdAt: Date;
updatedAt: Date;
}
Repetitive Patterns
When you have established a pattern in a file, Tab picks it up and continues it. Adding the tenth item to a list, the fifth route to a router, or the third column to a database schema -- Tab can predict each one because it has seen the preceding items.
// After you write these:
const routes = {
home: '/',
about: '/about',
blog: '/blog',
// Tab suggests:
contact: '/contact',
pricing: '/pricing',
};
Writing Tests
Test files are some of the most pattern-dense code in a project. Once you have established your describe / it structure and your first few assertions, Tab can often suggest the next test case based on what you have been testing. This is particularly valuable when writing comprehensive test suites where each test follows a similar structure.
describe('calculateDiscount', () => {
it('returns 20% discount for premium users', () => {
expect(calculateDiscount(100, 'premium')).toBe(80);
});
it('returns 10% discount for standard users', () => {
expect(calculateDiscount(100, 'standard')).toBe(90);
});
// Tab suggests:
it('returns no discount for free users', () => {
expect(calculateDiscount(100, 'free')).toBe(100);
});
});
Filling in Function Bodies
After you write a function signature with a clear name and typed parameters, Tab has strong signal about what the function should do and can often generate a reasonable body. The more descriptive your function name, the better the suggestion.
// After you write this signature, Tab suggests a full body:
async function fetchUserById(userId: string): Promise<User | null> {
// Tab generates the implementation
}
Tab Completion vs Traditional Autocomplete
To summarize the difference clearly:
| Aspect | Traditional Autocomplete | Cursor Tab |
|---|---|---|
| Source | Type info and API lookups | AI model trained on code |
| Scope | Single identifier at a time | Multi-line blocks |
| Predictability | Deterministic (shows all valid options) | Probabilistic (predicts most likely intent) |
| What it generates | Names, method signatures | Entire implementations |
| Context used | File's type system | File content, patterns, structure |
| Triggering | Typing or Ctrl+Space | Automatic as you type |
They are complementary rather than competing. Traditional autocomplete (which Cursor also supports) is precise and exhaustive -- it shows you every valid completion. Tab completion is predictive and opinionated -- it guesses what you specifically are trying to write.
Summary
Cursor's Tab completion is not an upgraded version of traditional autocomplete -- it is a fundamentally different tool. It uses an AI model to predict what you are about to write, can suggest multiple lines at once, and gets more accurate as it sees more of your file's patterns. Ghost text previews suggestions without interrupting your typing, and you accept with Tab, reject by continuing to type, or accept partially word by word with Cmd+Right.
The situations where Tab saves the most time are those with predictable patterns: boilerplate code, repetitive structures, and test writing. The more context your file provides, the better Tab's suggestions will be.
Key Takeaways
- Cursor's Tab completion is generative, not lookup-based -- it predicts what you will write next using an AI model, not just a list of valid identifiers
- Ghost text shows suggestions in grey before you accept them, with zero interruption to your typing flow
- Press Tab to accept a full suggestion, Escape or keep typing to reject it, and Cmd+Right to accept one word at a time from a longer suggestion
- Tab reads both above and below the cursor to understand your intent -- bidirectional context improves accuracy
- Tab is most valuable for boilerplate, repetitive patterns, and test writing where predictable structures give the model strong signal
- Toggle Tab completion on and off via Cmd+Shift+P when ghost text becomes a distraction
- Tab and traditional autocomplete are complementary -- Tab predicts intent while autocomplete enumerates valid completions
Quiz
Discussion
Sign in to join the discussion.

