Manuel Matuzović is a frontend developer from Vienna who’s passionate about accessibility, progressive enhancement, performance, and web standards. He’s one of … More about Manuel ↬
In this article, Manuel explains why Emmet is one of his favorite productivity tools for writing HTML and CSS, and how you can create custom Emmet snippets in Visual Studio Code to help you improve your front-end workflows even more.
Earlier this year, I shared the HTML boilerplate I like to use when starting new web projects with line-by-line explanations on my blog. It’s a collection of mostly <head> tags and attributes I usually use on every website I build. Until recently, I would just copy and paste the boilerplate whenever I needed it, but I’ve decided to improve my workflow by adding it as a snippet to VS Code — the editor of my choice.
Here’s a quick demo of the custom snippets I’ve created.
Snippets And Abbreviations In Visual Studio Code
VS Code comes built-in with custom user snippets and HTML and CSS snippets and abbreviations provided by Emmet.
For example, if you type p>a{Sign Up} in an HTML document and press Enter or Tab, Emmet will turn it into the following markup:
<p><a href="">Sign Up</a></p>
Note: Visit the Emmet docs to learn how to use the abbreviation syntax.
If we need this specific abbreviation regularly, we can save it as a snippet to improve our workflow even more.
Open the VS Code settings (Code → Preferences → Settings) and search for “Emmet Extensions Path”.
Click “Add Item”, enter the path to the folder where you’ve saved the snippets.json file you’ve created earlier and press “OK”.
That’s it. Now we’re ready to create snippets by adding properties to the html and css objects where the key is the name of the snippet and the value an abbreviation or a string.
Some Of My Custom HTML Snippets
Before we dive deep into snippet creation and I show you how I created a snippet for my HTML boilerplate, let’s warm up first with some small, but useful snippets I’ve created, as well.
Lazy Loading
Out of the box, there’s an img abbreviation, but there’s none for lazily loaded images. We can use the default abbreviation and just add the additional attributes and attribute values we need in square brackets.
Most pages I create consist of <header>, <main> and <footer> landmarks and an <h1>. The custom page abbreviation lets me create that structure quickly.
The abbreviation nav just creates a <nav> start and end tag by default, but what I usually need is a <nav> with a nested <ul>, <li> elements and links ( <a>). If there are multiple <nav> elements on a page, they should also be labeled, for example by using aria-label.
We start with a <nav> element with an aria-label attribute and a nested <ul>. ${1:Main} populates the attribute with the text “Main” and creates a tab stop at the attribute value by moving the cursor to it and highlighting it upon creation.
nav[aria-label='${1:Main}']>ul
Then we create four list items with nested links. The first item is special because it marks the active page using aria-current="page". We create another tab stop and populate the link with the text “Current Page”.
(li>a[aria-current='page']>{${2:Current Page}})
Finally, we add three more list items with links and the link text “Another page”.
The default style abbreviation only creates the <style> start and end tag, but usually when I use the <style> element I do it because I quickly want to test or debug something.
Alright, enough warming-up. Let’s create complex snippets. At first, I wanted to create a single snippet for my boilerplate, but I created three abbreviations that serve different needs.
Small
Medium
Full
Boilerplate Small
This is a boilerplate for quick demos, it creates the following:
Basic site structure,
viewport meta tag,
Page title,
<style> element,
A <h1>.
{ "!": "{<!DOCTYPE html>}+html[lang=${1}${lang}]>(head>meta:utf+meta:vp+{}+title{${2:New document}}+{}+style)+body>(h1>{${3: New Document}})+{${0}}"
}
Breakdown
A string with the doctype:
{<!DOCTYPE html>}
The <html> element with a lang attribute. The value of the lang attribute is a variable you can change in the VS code settings (Code → Preferences → Settings).
html[lang=${1}${lang}]
You can change the default natural language of the page by searching for “emmet variables” in VS Code settings and changing the lang variable. You can add your custom variables here, too.
The <head> includes the charset meta tag, viewport meta tag, <title>, and <style> tag. {} creates a new line.
Looks okay, but the meta:utf abbreviation creates the old way in HTML to define the charset and meta:vp creates two tab stops I don’t need because I never use a different setting for the viewport.
For me, that’s the perfect minimal debugging setup.
Boilerplate Medium
While I use the first boilerplate only for quick demos, the second boilerplate can be used for complex pages. The snippet creates the following:
Basic site structure,
viewport meta tag,
Page title,
.no-js/.js classes,
External screen and print stylesheets,
description and theme-color meta tag,
Page structure.
{ "!!": "{<!DOCTYPE html>}+html[lang=${1}${lang}].no-js>{<!-- TODO: Check lang attribute --> }+(head>meta:utf+meta:vp+{}+title{${1:🛑 Change me}}+{}+(script[type="module"]>{document.documentElement.classList.replace('no-js', 'js');})+{}+link:css+link:print+{}+meta[name="description"][content="${2:🛑 Change me (up to ~155 characters)}"]+{<!-- TODO: Change page description --> }+meta[name="theme-color"][content="${2:#FF00FF}"])+body>page"
}
Yeaaah, I know, that looks like gibberish. Let’s dissect it.
Breakdown
The doctype and the root element are like in the first example, but with an additional no-js class and a comment that reminds me to change the lang attribute, if necessary.
A script with a line of JavaScript. I’m cutting the mustard at the JS module support. If a browser supports JavaScript modules, it means that it’s a browser that supports modern JavaScript (e.g. modules, ES 6 syntax, fetch, and so on). I ship most JS only to these browsers, and I use the js class in CSS, if the styling of a component is different, when JavaScript is active.
A demonstration of all 3 CSS snippets applied to a div element.
User Snippets
At the beginning of this article, I mentioned that VS Code also provides custom snippets. The difference to Emmet snippets is that you can’t use abbreviations, but you can also define tab stops and make use of internal variables.
How to get the best out of user snippets could be a topic for another article, but here’s an example of a custom CSS snippet I’ve defined:
It takes some time to create these snippets, but it’s worth the effort because you can customize Emmet to your personal preferences, automate repetitive tasks and save time in the long run.
I’d love to see which snippets you use, so please share them with us in the comments. If you want to use my settings, you can find my final snippets.json on GitHub.