Emmet for HTML: A Beginner's Guide to Writing Faster Markup
The moment I realized I'd been writing HTML the slow way
I spent the first few months of learning web development typing every HTML tag by hand. Open the file, type <div>, type </div>, go back between them, start the next line, <p>, </p>. Over and over.
I remember building a simple card component — a title, some text, a button, wrapped in a container. Nothing complex. It took me almost ten minutes to type it all out, and most of that time wasn't thinking. It was just... typing angle brackets.
Then a classmate watched me do this and said, very calmly: "Why aren't you using Emmet?"
He typed div.card>h2+p+button and hit Tab.
The entire card structure appeared. All the tags, properly nested, properly indented, in about half a second.
I sat there for a moment. Then I said: "What was that?"
This blog is the answer to that question.
What Emmet Is
Emmet is a plugin — built into VS Code by default, and available for almost every other code editor — that expands short abbreviations into full HTML (and CSS) code.
You type a short expression that describes the structure you want. You press Tab. Emmet writes the full HTML for you.
That's it. No installation needed if you're on VS Code. No configuration. No learning curve beyond the abbreviation syntax itself — which is the point of this blog.
Emmet isn't a programming language. It's not a framework. It's a shortcut system. And the shortcut system is designed to feel like the HTML structure you're trying to create — once it clicks, you'll be surprised how natural it feels.
Why Bother?
You might be thinking: I'm still a beginner. HTML isn't hard. Why add another thing to learn?
Fair question. Here's my honest answer.
You're going to type a lot of HTML. If you work on anything real — even a personal project — you'll write the same structural patterns over and over: wrapper divs, lists of items, cards, forms, nav bars. The mechanical part of typing those tags is not where your brain should be spending energy.
Emmet handles the typing. You handle the thinking.
It also helps you think about HTML structure more clearly. When you write ul>li*5, you're explicitly thinking "I need an unordered list with five items." That mental model is good for learning, not just for speed.
And practically: every professional frontend developer uses Emmet or something like it. Getting comfortable with it early means it'll be second nature by the time you're building real things.
How Emmet Works in VS Code
If you're on VS Code — which I'd recommend for everything in this series — Emmet is already installed and active for HTML files.
Open any .html file. Start typing an Emmet abbreviation. When you're done, press Tab. VS Code expands it.
That's the entire workflow. Type, Tab, done.
A few things worth knowing:
Emmet only activates in HTML (and other supported file types like JSX, Pug, etc.) by default. If you're in a .js file and Tab doesn't expand, that's why.
Sometimes VS Code shows a suggestion in the autocomplete dropdown — you can press Enter from there instead of Tab. Either works.
If Tab isn't expanding and you're definitely in an HTML file, check that Emmet is enabled: open VS Code settings (Ctrl+,), search for "Emmet: Enabled", and make sure it's on.
Now let's actually learn the syntax.
Basic Elements: Just Type the Tag Name
The simplest Emmet abbreviation is just the name of the HTML element you want, without the angle brackets.
Type this and press Tab:
p
Expands to:
<p></p>
Type this and press Tab:
h1
Expands to:
<h1></h1>
Type this and press Tab:
section
Expands to:
<section></section>
Your cursor lands between the opening and closing tags, ready for you to type the content. Clean, fast, no angle bracket typing.
This works for every standard HTML element. div, span, ul, button, form, header, footer, nav — all of them.
Adding a Class: The Dot
To add a class to an element, use a dot — exactly like CSS selectors.
Type:
div.container
Expands to:
<div class="container"></div>
Type:
p.intro-text
Expands to:
<p class="intro-text"></p>
Multiple classes? Keep adding dots:
div.card.featured
Expands to:
<div class="card featured"></div>
The reason Emmet uses dots for classes is intentional — it mirrors how you'd select that element in CSS (.container, .card). Once you know CSS selectors, you already half-know Emmet.
Adding an ID: The Hash
Same idea, but with a hash symbol for IDs:
div#main
Expands to:
<div id="main"></div>
Combine with a class:
div#app.wrapper
Expands to:
<div id="app" class="wrapper"></div>
Again — mirrors CSS selector syntax exactly. #app.wrapper in CSS would select an element with id "app" and class "wrapper". Emmet uses the same notation to create it.
Attributes: Square Brackets
For attributes beyond class and ID — like src, href, type, placeholder — use square brackets:
a[href="https://github.com"]
Expands to:
<a href="https://github.com"></a>
input[type="email" placeholder="Enter your email"]
Expands to:
<input type="email" placeholder="Enter your email">
Note that input is a void element (no closing tag), and Emmet knows this — it generates the correct self-closing form automatically.
img[src="photo.jpg" alt="My photo"]
Expands to:
<img src="photo.jpg" alt="My photo">
Nesting Elements: The > Operator
This is where Emmet starts to feel genuinely useful. The > operator creates a parent-child relationship — the element on the right is nested inside the element on the left.
div>p
Expands to:
<div>
<p></p>
</div>
nav>ul>li
Expands to:
<nav>
<ul>
<li></li>
</ul>
</nav>
That three-level structure typed as nine characters. Compare that to writing it by hand:
<nav>
<ul>
<li></li>
</ul>
</nav>
Same result, fraction of the effort. And you're explicitly thinking about the hierarchy as you write the abbreviation — nav contains ul contains li.
Sibling Elements: The + Operator
The + operator creates sibling elements — elements at the same level, not nested.
h1+p
Expands to:
<h1></h1>
<p></p>
label+input
Expands to:
<label></label>
<input>
Combine with nesting:
div>h2+p+button
Expands to:
<div>
<h2></h2>
<p></p>
<button></button>
</div>
A card with a heading, paragraph, and button — the structure my classmate showed me — in one abbreviation.
Repeating Elements: The * Operator
The * operator repeats an element a specified number of times.
li*3
Expands to:
<li></li>
<li></li>
<li></li>
ul>li*5
Expands to:
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Five list items, complete with the parent ul. Manually, that's 14 lines. With Emmet, it's seven characters.
Combine with classes:
div.card*3
Expands to:
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
Three identical card containers. One abbreviation.
Numbering Repeated Items: $
When you repeat elements, you often want sequential numbers. The $ placeholder inserts an auto-incrementing number.
li.item-$*3
Expands to:
<li class="item-1"></li>
<li class="item-2"></li>
<li class="item-3"></li>
h2.section-$*4
Expands to:
<h2 class="section-1"></h2>
<h2 class="section-2"></h2>
<h2 class="section-3"></h2>
<h2 class="section-4"></h2>
Useful for generating numbered sections, slides, or any sequentially-named elements during prototyping.
Adding Text Content: {}
To include text content inside the element, use curly braces:
p{Hello, World}
Expands to:
<p>Hello, World</p>
a[href="#"]{Click here}
Expands to:
<a href="#">Click here</a>
Combine with repetition and $:
li{Item $}*3
Expands to:
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
Now you're generating both the structure and the placeholder content at the same time.
Going Back Up: The ^ Operator
When you're chaining with >, you keep going deeper. The ^ operator lets you climb one level back up.
div>p>span^button
Expands to:
<div>
<p><span></span></p>
<button></button>
</div>
The ^ moves button up out of <p> and places it as a sibling of <p> inside <div>.
Honestly, once abbreviations get complex enough to need ^, I often split them into two separate abbreviations instead. But for simpler structures, it's useful to know.
Grouping: Parentheses
Parentheses group parts of an abbreviation — useful when you want to repeat a multi-element structure.
(div>h2+p)*3
Expands to:
<div>
<h2></h2>
<p></p>
</div>
<div>
<h2></h2>
<p></p>
</div>
<div>
<h2></h2>
<p></p>
</div>
Three identical card structures — each with a heading and paragraph — from one abbreviation. This is genuinely useful when scaffolding a page with repeated sections.
The Full HTML Boilerplate: !
And here's the one that comes up in every single project. Type this into a blank .html file and press Tab:
!
Just an exclamation mark.
Expands to:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
A complete, valid HTML5 boilerplate. Everything you need to start a new HTML page: doctype declaration, <html> with language attribute, <head> with charset and viewport meta tags, a <title>, and an empty <body>.
One character. Tab. Full boilerplate.
This is the abbreviation I use literally every time I start a new HTML file. If you remember nothing else from this blog, remember ! followed by Tab.
A Real-World Example
Let me put several of these together into something resembling a real component. Say I want to scaffold a simple blog post card:
div.card>img[src="post.jpg" alt="Post image"]+div.card__content>h3{Post Title}+p{Post excerpt goes here.}+a[href="#"]{Read more}
Expands to:
<div class="card">
<img src="post.jpg" alt="Post image">
<div class="card__content">
<h3>Post Title</h3>
<p>Post excerpt goes here.</p>
<a href="#">Read more</a>
</div>
</div>
One line. A complete, structured blog card with an image, a content container, a heading, a paragraph, and a link. Every class, every attribute, properly nested.
That's the power of Emmet in practice.
Tips for Getting Comfortable
Type one abbreviation at a time and watch what it expands to. Don't try to memorise everything at once. The operators you'll use 90% of the time are >, +, *, ., #, and {}. Start with those.
Use ! every time you start a new HTML file. It'll become muscle memory within a week.
When you need a structure, try writing it in Emmet first. If it doesn't work the way you expect, fall back to typing it manually. No shame in that — Emmet is a tool, not a requirement.
The abbreviations in this blog cover what you'll actually use day to day. There's a full Emmet cheat sheet at docs.emmet.io if you ever want to explore the less-common syntax.
Emmet felt unnecessary until I started using it daily. Now typing raw HTML without it feels like writing code without autocomplete — technically possible, but slower than it needs to be. Learn the basics, use it on your next project, and it'll earn its place in your workflow.