Creating Custom VS Code Snippets for Faster Development
If you find yourself repeatedly writing the same code patterns, VS Code snippets can help. Let's explore how to create custom snippets that will boost your productivity.
What are VS Code Snippets?
Snippets are reusable code templates that expand into larger blocks of code when triggered. Instead of manually typing common patterns, you can:
- Type a short prefix
- Press
Tab
- Watch your snippet expand into a complete code block with customizable placeholders
Creating Your First Snippet
To get access to snippets:
- Open VS Code
- Navigate to File > Preferences > Configure User Snippets
- Keyboard shortcut:
Ctrl+Shift+P
(Windows/Linux) orCmd+Shift+P
(Mac), then search for "Snippets"
- Keyboard shortcut:
- Select a language-specific file (e.g., "javascript.json" for JavaScript snippets)
Now let's review the structure of a snippet. There are a few main pieces:
prefix
: The text you type to trigger the snippetbody
: The actual code template (string or array of strings)description
: Helpful text shown in the IntelliSense menu
And here's what that looks like as code:
{ "Snippet Name": { "prefix": "trigger", "body": [ "Your snippet content", "goes here", "$1" ], "description": "What this snippet does" } }
You can do more sophisticated things too with variables and placeholders which we will look at next.
Tab Stops and Placeholders
As you tab complete, you can used these numbered placeholders to configure where your cursor should stop next when you tab complete. Here's the syntax:
$1
,$2
,$3
: Ordered tab stops. Eg.$1
is where your cursor will end up after the first tab and then$2
.${1:default}
: Tab stop with default text$0
: Final cursor position- Multiple occurrences of the same number synchronize changes
You can also access some built-in variables to use in your snippets:
$TM_FILENAME Current file name $TM_FILENAME_BASE File name without extension $CURRENT_YEAR Current year (e.g., 2024) $CURRENT_DATE Current date (e.g., 10/31/2024) $CLIPBOARD Contents of your clipboard $WORKSPACE_NAME Current workspace name $LINE_COMMENT Line comment for current language
That's a lot of theory, but this stuff gets easy when you actually build stuff with it so here are some examples to get you going:
Snippet Examples
React TypeScript Component
{ "React TypeScript Component": { "prefix": "rts", "body": [ "import React from 'react'", "", "interface ${1:${TM_FILENAME_BASE}}Props {", " ${2:// Props}", "}", "", "export const ${1:${TM_FILENAME_BASE}} = ({", " ${3:// Destructured props}", "}: ${1:${TM_FILENAME_BASE}}Props): JSX.Element => {", " return (", " <div className=\"$4\">", " $0", " </div>", " )", "}", "", "export default ${1:${TM_FILENAME_BASE}}", "" ], "description": "React TypeScript component with Props interface" } }
Using this snippet:
- Create a new file (e.g.,
Button.tsx
) - Type
rts
and press Tab - Component name automatically matches filename (e.g., "Button")
- Press Tab to move to props interface section
- Type your props (e.g.,
onClick: () => void
) - Press Tab to move to props destructuring
- Type the same props (e.g.,
onClick
) - Press Tab to add your className
- Press Tab one final time to move cursor inside the div
Example output after these steps:
import React from 'react' interface ButtonProps { onClick: () => void } export const Button = ({ onClick }: ButtonProps): JSX.Element => { return ( <div className="button-primary"> {/* Cursor ends up here */} </div> ) } export default Button
Enhanced Console Logger
{ "Smart Console Log": { "prefix": "lgx", "body": [ "console.log('[${TM_FILENAME_BASE}]', '${1:label}:', ${2:value});$0" ], "description": "Console log with filename context and value inspection" } }
Using this snippet:
- Type
lgx
and press Tab - Type the label for your log (e.g., "userData")
- Press Tab
- Type the variable name you want to log
- Press Tab to move to the next line
Example usage in a file named UserService.ts
:
const user = await fetchUser(id); lgx↹ // After typing "userData" and pressing Tab: console.log('[UserService]', 'userData:', user); // Console output: [UserService] userData: { id: 1, name: 'John' }
Error Handler with Async/Await
{ "Try-Catch Async": { "prefix": "tca", "body": [ "try {", " ${1:// Async operation}", "} catch (error) {", " console.error(", " `[${TM_FILENAME_BASE}] ${2:Error message}:`,", " error instanceof Error ? error.message : error", " );", " ${3:throw error;}$0", "}" ], "description": "Try-catch block with proper error handling" } }
Using this snippet:
- Type
tca
and press Tab - Type your async operation (e.g.,
const user = await fetchUser(id);
) - Press Tab
- Enter a descriptive error message (e.g.,
Failed to fetch user
) - Press Tab
- Modify or keep the error handling (e.g., change to
throw new Error('User not found');
) - Press Tab to move to the next line
Example usage in UserService.ts
:
async function getUser(id: string) { tca↹ // After completing all steps: try { const user = await fetchUser(id); } catch (error) { console.error( `[UserService] Failed to fetch user:`, error instanceof Error ? error.message : error ); throw new Error('User not found'); } }
[Rest of the document remains the same...]
Scope-Specific Snippets
When you were selecting how to create a snippet you might of noticed a lot of options. You can use these file options to scope your snippets to certain file types.
Here are some examples of what those files look like:
javascript.json
: JavaScript filestypescript.json
: TypeScript filesjavascriptreact.json
: JSX filestypescriptreact.json
: TSX filesmarkdown.json
: Markdown fileshtml.json
: HTML filescss.json
: CSS files
Global Snippets
For snippets that work across all file types:
- Choose "New Global Snippets file" when creating snippets
- Save with a descriptive name (e.g.,
general-snippets.code-snippets
)
Snippets are a simple way to speed up your development workflow. By investing a little time in creating well-thought-out snippets, you can spend more time-solving problems and less time writing boilerplate.
Start with a few snippets for your most common patterns and gradually build your library as you identify more opportunities for automation in your workflow.