← Back to DevBytes

Vim Code Snippets: Complete Guide

Introduction to Vim Code Snippets

Code snippets are one of the most powerful productivity features available to developers using Vim. They allow you to define reusable templates that expand into full blocks of code with a simple trigger word and keystroke. Whether you're writing boilerplate HTML, repetitive function definitions, or complex language constructs, snippets can save you thousands of keystrokes every day.

What Are Vim Code Snippets?

A snippet is a short, predefined piece of text that expands into a larger template when triggered. In Vim, snippets typically work by typing a trigger keyword followed by a expansion key (usually <Tab>). The expanded text can include placeholders, tab stops, mirrors, and even dynamic content generated by shell commands or VimScript expressions.

For example, typing def followed by <Tab> could expand into a complete Python function definition with your cursor positioned at the function name, ready to type.

Why Snippets Matter

Setting Up a Snippet Engine in Vim

Vim does not include snippet support out of the box. You need a snippet engine plugin. The two most popular options are UltiSnips and vim-snipmate. We'll cover both, with a focus on UltiSnips due to its richer feature set.

Installing UltiSnips

If you use vim-plug, add the following to your ~/.vimrc:

" UltiSnips requires Python support in Vim
Plug 'SirVer/ultisnips'

" Optional: a community-maintained snippet collection
Plug 'honza/vim-snippets'

let g:UltiSnipsExpandTrigger = '<tab>'
let g:UltiSnipsJumpForwardTrigger = '<tab>'
let g:UltiSnipsJumpBackwardTrigger = '<s-tab>'

After adding the lines, run :PlugInstall inside Vim. The vim-snippets repository provides hundreds of ready-to-use snippets for many languages.

Installing vim-snipmate

For a lighter-weight alternative, you can use vim-snipmate:

Plug 'garbas/vim-snipmate'
Plug 'honza/vim-snippets'

SnipMate uses a simpler snippet syntax and is a good choice if you want minimal dependencies.

Writing Your First Snippet

UltiSnips stores snippet files in ~/.vim/UltiSnips/ by default. Each file is named after the filetype, for example python.snippets, javascript.snippets, or html.snippets.

Basic Syntax

The basic structure of an UltiSnips snippet is:

snippet trigger "description" [options]
expanded text
endsnippet

Let's create a simple Python function snippet. Create or edit ~/.vim/UltiSnips/python.snippets:

snippet def "Python function definition" b
def ${1:function_name}(${2:args}):
    """${3:Docstring.}"""
    ${0:${VISUAL:pass}}
endsnippet

Now, in a Python file, type def and press <Tab>. The snippet expands, and your cursor jumps to function_name. Press <Tab> again to move to args, then to the docstring, and finally to the function body.

Snippet Options

The letter after the description controls behavior. Common options include:

Advanced Snippet Features

Placeholders and Tab Stops

Placeholders are numbered positions the cursor jumps to when you press <Tab>. The syntax is ${1:default_text}. The ${0} tab stop is special — it marks the final cursor position.

snippet for "For loop" b
for ${1:i} in range(${2:0}, ${3:n}):
    ${0:pass}
endsnippet

You can also use simple tab stops without default text:

snippet class "Python class" b
class ${1:ClassName}(${2:object}):
    def __init__(self${3:, args}):
        super().__init__()
        ${0:pass}
endsnippet

Mirrors

Mirrors duplicate the value of a tab stop at multiple locations. Use the tab stop number without braces:

snippet const "JavaScript const" b
const ${1:name} = ${2:value};
console.log(${1}, ${2});
endsnippet

When you type the variable name at tab stop 1, it automatically appears in the console.log statement as well.

Visual Placeholders

Visual placeholders let you wrap selected text in a snippet. Select text in visual mode, press <Tab> (or your configured trigger), and the selected text is placed at ${VISUAL}:

snippet try "Try/except block" b
try:
    ${VISUAL}
except ${1:Exception} as e:
    print(f"Error: {e}")
endsnippet

Shell Commands

UltiSnips can execute shell commands using backticks. This is useful for inserting dynamic content like dates or usernames:

snippet header "File header" b
# -*- coding: utf-8 -*-
# Created on: `!v strftime("%Y-%m-%d")`
# Author: `!v system('whoami')[:-1]`
# Description: ${1:Description}
endsnippet

The !v prefix tells UltiSnips to evaluate the expression as VimScript. You can also use ! for raw shell output:

snippet date "Current date" b
`date +%Y-%m-%d`
endsnippet

Python Interpolation

One of UltiSnips' most powerful features is Python interpolation. You can embed Python code between `!p and ` markers to generate dynamic snippet content:

snippet prop "Python property" b
@property
def ${1:name}(self):
    """Get ${1/name/_/ }."""
    return self._${1}

@${1}.setter
def ${1}(self, value):
    self._${1} = value
endsnippet

Here's a more advanced example that generates a list of arguments:

snippet init "Python __init__ with args" b
def __init__(self, `!p
args = []
for i in range(int(t[1])):
    args.append(f"arg{i+1}")
snip.rv = ", ".join(args)
`):
    `!p
for i in range(int(t[1])):
    snip.rv += f"self.arg{i+1} = arg{i+1}\n    "
`${0:pass}
endsnippet

When you trigger this snippet and type 3 at the first tab stop, it generates an __init__ method with three arguments and three assignment statements.

Nested Snippets

UltiSnips supports nesting snippets within other snippets. You can expand a snippet while inside another snippet's tab stop. This is useful for building complex structures incrementally:

snippet ifmain "If __name__ == '__main__'" b
if __name__ == '__main__':
    ${0:pass}
endsnippet

snippet main "Main function" b
def main():
    ${0:pass}

if __name__ == '__main__':
    main()
endsnippet

Snippet Examples by Language

HTML Snippets

snippet html5 "HTML5 boilerplate" b
<!DOCTYPE html>
<html lang="${1:en}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>${2:Document Title}</title>
</head>
<body>
    ${0:}
</body>
</html>
endsnippet

snippet a "Anchor tag" b
<a href="${1:#}">${2:Link Text}</a>
endsnippet

JavaScript Snippets

snippet fn "Arrow function" b
const ${1:name} = (${2:args}) => {
    ${0:}
};
endsnippet

snippet async "Async function" b
async function ${1:name}(${2:args}) {
    try {
        ${0:}
    } catch (error) {
        console.error(error);
    }
}
endsnippet

snippet fetch "Fetch with async/await" b
const response = await fetch('${1:url}', {
    method: '${2:GET}',
    headers: {
        'Content-Type': 'application/json',
    },
    ${3:body: JSON.stringify(${4:data}),}
});
const ${5:data} = await response.json();
endsnippet

React Snippets

snippet rfc "React functional component" b
import React from 'react';

const ${1:ComponentName} = (${2:props}) => {
    return (
        <div>
            ${0:}
        </div>
    );
};

export default ${1:ComponentName};
endsnippet

snippet useState "useState hook" b
const [${1:state}, set${1/(.)/\u$1/}] = useState(${2:initialValue});
endsnippet

snippet useEffect "useEffect hook" b
useEffect(() => {
    ${0:}
}, [${1:dependencies}]);
endsnippet

Managing Snippets Across Projects

Filetype-Specific Snippets

UltiSnips automatically loads snippet files based on the current filetype. You can also create snippets for multiple filetypes by separating them with a dot, for example html.css.snippets loads for both HTML and CSS files.

Project-Level Snippets

You can configure UltiSnips to load snippets from your project directory. Add this to your ~/.vimrc:

let g:UltiSnipsSnippetDirectories = ["UltiSnips", "mysnippets"]

" Load project-local snippets
autocmd BufRead,BufNewFile * let &runtimepath .= ',' . getcwd() . '/.vim'

Then place project-specific snippets in .vim/UltiSnips/ within your project root.

Sharing Snippets with a Team

Commit your snippet files to a shared repository or include them in your project's dotfiles. The vim-snippets repository is a great starting point — fork it and customize for your team's conventions.

Best Practices

Keep Snippets Focused

Each snippet should do one thing well. Avoid creating massive snippets that generate entire files unless you use them frequently. Smaller, composable snippets are easier to maintain and combine.

Use Meaningful Triggers

Choose trigger words that are short but memorable. def for function definitions, cls for classes, ifmain for the main guard. Avoid triggers that conflict with common words you type regularly.

Provide Default Values

Always include sensible default text in placeholders. This makes snippets self-documenting and helps you understand what each field expects:

snippet req "Express require" b
const ${1:express} = require('${2:express}');
endsnippet

Test Snippets Thoroughly

After writing a snippet, test it in a real file. Check that tab stops are in a logical order, mirrors work correctly, and Python interpolation produces the expected output.

Version Control Your Snippets

Store your custom snippets in a dotfiles repository under version control. This ensures you never lose your snippets and can sync them across machines.

Don't Over-Snippet

Resist the urge to create snippets for everything. Snippets are most valuable for code you write frequently. If you create a snippet for something you use once a month, you'll forget the trigger and never use it.

Learn from Community Snippets

Browse the vim-snippets repository to see how experienced users structure their snippets. You'll discover patterns and techniques you can apply to your own workflow.

Debugging Snippets

If a snippet doesn't expand, check the following:

Conclusion

Vim code snippets are a transformative productivity tool that can dramatically reduce the time you spend on repetitive coding tasks. By investing a few hours in setting up a snippet engine like UltiSnips and writing custom templates for your most common patterns, you'll reap returns every single day. Start with simple snippets for your most frequent boilerplate, gradually incorporate advanced features like Python interpolation and visual placeholders, and keep your snippet collection under version control. Over time, your snippet library becomes a personalized coding assistant that knows exactly how you like to write code, letting you focus on solving problems rather than typing syntax.

— Ad —

Google AdSense will appear here after approval

← Back to all articles