Snippets are templates that make it easier to add the stuff you type all the time. Most often they are used for code you type a lot like for loops or if statements, but they can be any text that you type a lot.
I like to use them for boilerplate code that I find tedious to write. Things like the spec-style functions wrapping my tests (describe()
and it()
blocks) or a Ruby class definition with # frozen_string_literal: true
as the first line.
They also come in handy for making it easy to follow your team's style conventions. If you like to organize your model spec files with sections for associations, validations, instance methods, and class methods, you can write a snippet to set that up. Or if you have conventions for writing your Storybook stories, you can write a snippet to make it easy for everyone on the team to follow.
The nitty-gritty
VSCode provides some snippets out of the box. And there are extensions you can install which will add more to your environment. And even more useful, you can write your own!
You can organize your snippets however you like. VSCode supports global snippets which are available in all languages or on a per-language basis. And you can even write snippets per workspace (though I don't do that very often).
To add a snippet, go to the menu bar and select Code (or File) > Preferences > User Snippets. Then choose the scope of the snippet you want to add.
When you see a token that starts with a $
in the body of the snippet, that's a placeholder. When using a snippet, you can quickly jump to the next placeholder with Tab. Then you can edit the placeholder or jump to the next one. The string after the colon (if any) is the default text, for example, "element" in ${1:element}. Placeholder traversal order is ascending, starting from 1. $0
is an optional special case that always comes last, and exits snippet mode with the cursor at the specified position.
You can find the full snippet docs on VSCode's website.
In this post, I'll show you some of the fun things you can do with user snippets. And you can find all of my favorites in my snippets repo on Github. Please take them and use them! Or feel inspired and write your own!
Basic snippets
Insert text
The simplest snippet you can set up is one to just insert text. I use this for my debugger statements in all my coding languages.
I set up the same prefix (the trigger text) across all my coding languages and let the snippet handle inserting the correct text.
In Javascript, the snippet looks like this.
"debugger": {
"prefix": "db",
"body": [
"debugger"
],
"description": "debugger"
}
And in Ruby, it looks like this.
"pry": {
"prefix": "db",
"body": [
"require \"pry\"; binding.pry"
],
"description": "debugger"
}
Multiple placeholders for you to add custom text
Besides inserting text, you'll probably want to insert some customizable boilerplate most frequently.
My most used snippets are the describe
and it
blocks I use in tests. It gives me the wrapping functions and then lets me add the description string.
By using placeholders, I can control where my cursor goes and tab when I'm done typing and want to move to the next location.
For Javascript files (*.js), the snippets look like this
"test describe": {
"prefix": "describe(",
"body": [
"describe(\"$1\", () => {",
" $0",
"})"
],
"description": "jest describe block"
},
"test assertion (it)": {
"prefix": "it(",
"body": [
"it(\"$1\", () => {",
" $0",
"})"
],
"description": "jest it assertion"
}
I use those same prefixes to get the same functionality in Ruby (with an extra context
block since that doesn't exist in Jest specs). And that looks like this.
"test describe": {
"prefix": "describe ",
"body": [
"describe \"$1\" do",
" $0",
"end"
],
"description": "spec describe block"
}
"test assertion": {
"prefix": "it ",
"body": [
"it \"$1\" do",
" $0",
"end"
],
"description": "spec it assertion"
}
Intermediate snippets
Use the filename
Sometimes you'll want to use the filename in the body of a snippet.
Let's say you have a React component and you want to fill in your normal functional component boilerplate. By using the $TM_FILENAME_BASE variable, you get the filename without its extension for free. VSCode provides a lot of variables for you to use in your snippets.
"functional component": {
"prefix": "fc",
"body": [
"import React from 'react'",
"",
"export function $TM_FILENAME_BASE(props) {",
" return (",
" $0",
" )",
"}",
],
"description": "boilerplate for a React functional component"
}
Use the same placeholder in multiple places
We can also use a snippet to insert the same custom text in multiple places.
I use this to nicely format my console log statements. This snippet has multiple placeholders, but the second placeholder's default value is the first placeholder's value which also has a default value. It might make more sense when you see it in action.
"Print to console": {
"prefix": "log",
"body": [
"console.log('$1:', ${2:${1:loggedValue}})"
],
"description": "Log output to console"
}
Advanced snippets
Use the filename but mutate it in some way
What if you want to use the filename but change the case? Or use only part of it?
You can do both of those things via variable transforms. There are a few parts to a transform.
- The variable or placeholder you want to transform
- A regular expression to match against the value of the variable or placeholder (before transformation)
- A format string that tells the snippet how to transform the text
- Any options you want to pass to the regex (
i
for case insensitive, etc.)
Each of these parts is separated by a /
. This can make reading the regex a bit challenging.
For example, let's look at a snippet that you could use in a test file to give you the boilerplate for a component test. It takes a file named FancyComponent.test.js
and gives you FancyComponent
in the snippet body.
"testFile": {
"prefix": "test",
"body": [
"import React from 'react'",
"import { ${TM_FILENAME/(.*)\\.test\\..+$/$1/} } from '../${TM_FILENAME/(.*)\\.test\\..+$/$1/}'",
"",
"describe('${TM_FILENAME/(.*)\\.test\\..+$/$1/}', () => {",
" beforeEach(() => {",
" $2",
" })",
"",
" describe('render', () => {",
" it('renders correctly', () => {",
" $3",
" })",
" })",
"})"
],
"description": "boilerplate for a component test"
}
Let's break down the variable transform, ${TM_FILENAME/(.*)\\.test\\..+$/$1/}
- The variable:
TM_FILENAME
- The regex:
(.*)\\.test\\..+$
- The
\\.
is confusing but this is a literal.
. In the snippet, we need to double-escape the.
. This is what it would look like as an unescaped regex (like you might use in code)
- The
- The format string:
$1
- This refers to the first capture group. You can do many different capture groups and combine/format them how you need.
- The regex options: None
There are also some built-in transformations for you. You can transform the case with upcase
, downcase
capitalize
camelcase
, or pascalcase
.
"class": {
"prefix": "class ",
"body": [
"# frozen_string_literal: true",
"",
"class ${TM_FILENAME_BASE/(.*)/${1:/pascalcase}/g}",
" $0",
"end"
],
"description": "class boilerplate"
}
And we can combine both of those approaches. If we have a Ruby spec file and we want a snippet for the test boilerplate, we can use part of the file name and transform the case all in one go.
The following snippet takes the file name like fancy_model_spec.rb
and transforms it to FancyModel
.
"vanilla spec": {
"prefix": "spec ",
"body": [
"# frozen_string_literal: true",
"",
"require \"rails_helper\"",
"",
"RSpec.describe ${TM_FILENAME_BASE/^(.*)_spec$/${1:/pascalcase}/} do",
" describe \"$1\" do",
" $0",
" end",
"end"
],
"description": "spec boilerplate"
}
1 placeholder, multiple places with a transform
Building on that, we can also transform our text in just one of the instances of a placeholder that we use multiple times.
This is helpful when we want the same text but to change the case in one of the locations.
"useState": {
"prefix": "usestate",
"body": [
"const [${1:stateName}, set${1/(.)/${1:/upcase}/}] = useState([$2])"
]
}
Complex regex transform
Like I alluded to earlier in this post, when you're doing a variable or placeholder transform, the world is your oyster. I used Storybook on a recent project and I wanted to convert the filename, FancyComponent.stories.js
into a kebab cased story <fancy-component>
. This proved more challenging than I thought so I'm including an abbreviated example here just for fun 🙃
"kebab case example": {
"prefix": "kebab",
"body": [
"<${TM_FILENAME/([A-Z][a-z]*)([A-Z][a-z]*)*\\.stories\\..+$/${1:/downcase}${2:+-}${2:/downcase}/g}>"
],
"description": "kebab case example"
}
Snippets are powerful. They can speed up your typing and reduce the number of syntax errors due to missing closing tags. They're also fun to play with and create. Work smarter not harder 🤗
Find related posts:Developer workflowTips & tricks