Emmet: Wrap with Abbreviation
In lesson 14 you learned to expand a single shorthand line into complete HTML. But in real development, the scenario of already having code written is far more common — for example, you've already written a bunch of
<li>items and suddenly realize they're missing an outer<ul>wrapper. Manually adding the wrapper means repeating 4–5 lines per occurrence. This lesson teaches Emmet's Wrap with Abbreviation action — select code + type shorthand = one-click wrapping. This is the second core action in Emmet's editor operations.
1. What You'll Learn
- The core mechanism of Wrap with Abbreviation: select code + shorthand = wrapping
- Trigger methods: VSCode Command Palette (
Ctrl+Shift+P→Emmet: Wrap with Abbreviation); WebStormCtrl+Alt+J, SublimeCtrl+Shift+G, etc. - Single-element wrapping:
<p>text</p>→ one-click outer wrapper withdiv.wrapper - Multi-line batch wrapping: select 3 lines →
ul>li*3bulk restructure - Nested wrapping: select text →
a[href="..."]one-click link insertion
2. A Frontend Developer's Real Story
(1) Pain Point: You've Written the HTML, Then Realize You Forgot the Outer Wrapper
Alice inherits code from her colleague Bob. Bob wrote a blog's "Related Posts" module but forgot to wrap it with <ul>:
<li><a href="/post-1">Getting Started with Vue 3</a></li>
<li><a href="/post-2">React Hooks in Practice</a></li>
<li><a href="/post-3">Advanced TypeScript</a></li>
Alice wants to add a <ul class="related-posts"> to wrap the 3 <li> items. She tries doing it manually: copy the <ul> opening tag before the first <li>, copy </ul> after the third <li> — 2 copy-paste operations. If there are 5 such gaps across the codebase (blog post page, list page, detail page, archive page, search page), that's 10 copy-paste operations + 5 class name spelling checks.
Even worse, she often makes mistakes: pasting </ul> after a <li> accidentally places it in the middle (<li><a>...</a></li></ul>), breaking the DOM structure. Alice thinks: it's literally just "adding an outer wrapper" — why is it so tedious? Isn't there a "select + type shorthand = 1-step wrapping" method?
(2) The Wrap with Abbreviation Solution
Wrap with Abbreviation is Emmet's "reverse Expand Abbreviation" — not expanding from a blank slate, but adding a wrapper around existing code.
Alice's solution:
- Select all 3
<li>elements (column-select withAlt+mouse drag, orCtrl+Lto select lines) - Press
Shift+Alt+,to trigger Wrap - Type the shorthand
ul.related-posts> - Auto-expands to the complete structure with the outer
<ul>
With this single technique, Alice reduces fixing 5 missing wrappers from 10 copy-paste operations + 5 checks to 5 "select + Wrap" operations. Speed improvement of 3–5x, with zero typos (Emmet auto-generates class names).
(3) Benefits
Wrap with Abbreviation is the "bridge" in Emmet's editor operations — accelerating the "write first, optimize later" workflow by 3–5x. Combined with lesson 14's Expand Abbreviation (expanding from scratch) and lesson 16's Balance/Next Edit Point (editing acceleration), Emmet's complete "input → expand → edit → wrap" workflow is now in place. After this lesson, Alice's time for adding wrappers, inserting containers, and bulk restructuring drops from 5 minutes to 1 minute.
3. Core Definition of Wrap with Abbreviation
Wrap with Abbreviation is Emmet's action for rewriting existing code — wrapping selected code fragments with a new shorthand.
| Dimension | Detail |
|---|---|
| Purpose | Adds a wrapper around selected code, restructures according to the new shorthand |
| Trigger Key | VSCode Shift+Alt+, (comma); other editors Ctrl+Shift+A |
| Prerequisites | Must have selected code (without selection, it calls Match Tag Pair to wrap the context) |
| Wrap Position | Places selected content inside the last element by default (use $# placeholder to override) |
| Multi-line Support | * marks repeating elements; * without a number means "repeat according to selected line count" |
$# placeholder — this is the key extension that differentiates Wrap from Expand.
4. Trigger Methods: Editor Comparison
Wrap with Abbreviation has significantly different trigger keys across editors because this action is relatively new (added after 2013), and implementation progress varies by editor.
| Editor | Default Trigger Key | Command Palette | Notes |
|---|---|---|---|
| VSCode | None by default (use Command Palette) | Emmet: Wrap with Abbreviation |
Opens an input box directly |
| WebStorm / IntelliJ | Ctrl+Alt+J |
Emmet: Wrap with Abbreviation |
Popup for shorthand input |
| Sublime Text | Ctrl+Shift+G (requires Emmet plugin) |
emmet: wrap |
Popup for shorthand input |
| Atom | Ctrl+Shift+A |
Emmet: Wrap with Abbreviation |
Auto-select code prompt |
Shift+Alt+, in VSCode is Edit > Format Document, not Wrap. The community often custom-binds Shift+Alt+, to Wrap, but requires explicit binding in keybindings.json. The Command Palette (Ctrl+Shift+P → Emmet: Wrap with Abbreviation) is the most reliable entry point — supported by every editor. Other editors may require selecting code before pressing the shortcut. First-time use should start with the Command Palette: trigger + input box + Enter — 3 steps.
5. Four Wrapping Modes
Wrap with Abbreviation supports 4 wrapping modes, covering 4 common needs: adding an outer wrapper, adding siblings, bulk restructuring, and nested wrapping.
(1) Single-Element Wrapping: Add an Outer Layer
Select 1 element, wrap with 1 shorthand. Common scenario: originally <p>text</p>, now needs to be wrapped inside <div class="wrapper">.
(2) Multi-Line Batch Wrapping: Select N Lines → Bulk Restructure
Select multiple consecutive lines, use * to mark repeating elements. The key difference is * without a number — meaning "auto-repeat based on selected line count".
(3) Nested Wrapping: Select Text → Add Inner Tag
Select a piece of text or a tag, use a shorthand to embed it inside a new element. This is the common pattern for "adding links, adding styles, adding semantics".
(4) Combined Wrapping: Select + Nest + Multiple Attributes
Simultaneously use select + nesting + custom attributes + multiple classes. This is Wrap's "ultimate form".
6. Hands-On Examples
The following 4 examples cover Wrap with Abbreviation's 4 wrapping modes.
▶ Example: Single-Element Wrapping <p>text</p> → div.wrapper (Difficulty ⭐)
The most common Wrap scenario — adding an outer container to a single element.
Original code (in an HTML file):
<p>Hello World</p>
Steps:
- Select
<p>Hello World</p>(drag with mouse orCtrl+L) - Press
Shift+Alt+,to trigger Wrap - Type the shorthand
div.wrapper - Press Enter to confirm
Expansion:
<div class="wrapper">
<p>Hello World</p>
</div>
Output:
TEXT 📖 Display onlyExplanation: After selecting `<p>Hello World</p>` and invoking Wrap, Emmet treats the entire `<p>` as the "wrapped content" and generates the outer structure from the `div.wrapper` shorthand. By default, Wrap places the selected content inside the **last element** — here `<p>` becomes a child of `<div>`. This is the most direct single-element wrapping scenario: a previously isolated `<p>` is now wrapped by `<div class="wrapper">`. Emmet auto-indents — `<p>` is indented by 2 spaces, consistent with lesson 06's implicit tag rules. This single step replaces 5 manual operations (copy opening tag, paste, adjust indentation, copy closing tag, paste).
▶ Example: List Wrapping — Select 3 <li> → ul.nav (Difficulty ⭐⭐)
Multi-line batch wrapping — select 3 <li> items and one-click wrap with a nav container.
Original code:
<li><a href="/home">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
Steps:
- Select all 3 lines (drag 3 lines with mouse, or
Ctrl+Lfor 1 line +Ctrl+Shift+Lfor multi-line) - Press
Shift+Alt+,to trigger Wrap - Type the shorthand
ul.nav> - Press Enter to confirm
Expansion:
<ul class="nav">
<li><a href="/home">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
Output:
TEXT 📖 Display onlyExplanation: Select 3 lines, invoke Wrap, type `ul.nav>`. Emmet treats `ul.nav>` as "the selected 3 lines become children of ul". Note: here **`>` is key** — it indicates "selected content as children". If the shorthand was written as `ul.nav` (without `>`), Emmet would place the 3 `<li>` elements as siblings of `<ul>` (incorrect structure). `>` determines the "wrap position" — whether it's child-node wrapping or sibling wrapping. Common rule: by default, use `>` to explicitly mark "child-node wrapping"; use `+` for "sibling addition".
▶ Example: Link Wrapping — Select text → a[href="..."] (Difficulty ⭐)
Nested wrapping — select a piece of text and wrap it with a link tag.
Original code:
<p>Visit our website for more information.</p>
Steps:
- Select
our website(double-click or drag) - Press
Shift+Alt+,to trigger Wrap - Type the shorthand
a[href="https://example.com"] - Press Enter to confirm
Expansion:
<p>Visit <a href="https://example.com">our website</a> for more information.</p>
Output:
TEXT 📖 Display onlyExplanation: Select the 11 characters of `our website` (excluding surrounding spaces), invoke Wrap, type `a[href="https://example.com"]`. Emmet treats the entire `<a>` tag as the "wrap template", with the selected content becoming the text inside `<a>`. Note: this scenario doesn't need `>` — because `<a>` is a leaf node (no children to position). **Key detail**: in `a[href="..."]`, `href` is an attribute and the wrapped content is text — `>` is unnecessary. This "plain text → text inside tag" conversion is extremely common in Emmet.
▶ Example: Combined Wrapping — Select Welcome → header.container>h1.title (Difficulty ⭐⭐)
Combined wrapping — select + nest + custom class + multi-layer structure.
Original code:
<h1>Welcome</h1>
Steps:
- Double-click to select the text
Welcome(text only, not the<h1>tag) - Press
Shift+Alt+,to trigger Wrap (VSCode users: Command PaletteCtrl+Shift+P→Emmet: Wrap with Abbreviation) - Type the shorthand
header.container>h1.title - Press Enter to confirm
Expansion:
<header class="container">
<h1 class="title">Welcome</h1>
</header>
Output:
TEXT 📖 Display onlyExplanation: This example combines Wrap + Expand. `header.container>h1.title` simultaneously includes 3 Emmet mechanisms: ① `header.container` — tag + class; ② `>` — child nesting; ③ selected content placed inside the last element (h1). Emmet expands according to the "header > h1" two-layer structure, placing the selected text `Welcome` as the text content of the last element (h1). This single step replaces 5 manual operations: write `<header class="container">`, newline, write `<h1 class="title">`, write Welcome, write `</h1></header>`. **Key detail**: select **text only**, not the entire `<h1>...</h1>` tag — because Wrap defaults to "placing selected content as-is inside the last element of the generated snippet" (official docs). If you select the entire `<h1>Welcome</h1>`, the result would be `<h1 class="title"><h1>Welcome</h1></h1>` (nested h1, invalid HTML). **Note the indentation**: Emmet auto-indents h1 by 2 spaces (header is the container), consistent with lesson 04's nesting rules.
7. Common Shorthand Quick Reference
Wrap with Abbreviation uses the same shorthands as Expand Abbreviation — any Emmet shorthand can be used as a Wrap parameter. Here are 4 commonly used shorthand types:
| Scenario | Shorthand | Effect |
|---|---|---|
| Add outer wrapper | div.wrapper |
Selected + div outer |
| Add semantics | section.hero |
Selected + section semantic tag |
| Add navigation | ul.nav>li* |
Selected N lines + ul/li structure |
| Add link | a[href="..."] |
Selected text + a tag |
| Add header | header.container>h1.title |
Selected + multi-layer nesting |
*>3 and *3 are different — *>3 in Wrap means "repeat selected lines × 3" (e.g., ul>li*5 with 2 selected lines → 10 output lines); *3 always repeats 3 times. In Wrap, * (without a number) = auto-repeat based on selected line count is the most common.
❓ FAQ
Shift+Alt+, does nothing — VSCode's default "Format" shortcut pops up instead?Shift+Alt+F is "Format Document". You may have misremembered — Wrap's actual shortcut is Shift+Alt+, (comma key, to the right of the M key). If it still doesn't work, use the Command Palette fallback: Ctrl+Shift+P → Emmet: Wrap with Abbreviation.<p>, and after Wrap only the outer <div> remains?>. For example, div.wrapper without > won't produce a nested structure — Emmet will only add <div> as a "sibling node beside the selected content". Wrap's core rule is "selected content = child of the last element" — you must explicitly express the "wrap position" using >. Fix: rewrite the shorthand as div.wrapper>.*N explicitly. ul>li*5 with 3 selected lines → 5 output lines (ignoring selected line count). But the more common pattern is * (without a number) = auto-repeat based on selected line count. This "auto by line count" is a core Wrap feature — it saves you from having to count how many lines you selected.$# placeholder for? When should I use it?$# is Wrap's unique "output position" placeholder — it controls where the selected content is placed in the Wrap result. Syntax: ul>li[title=$#]*>{$#}+img[alt=$#]. This shorthand means: the selected content appears in 3 places simultaneously (li's title attribute, li's text, img's alt attribute). Common scenario: copying a CSS comment to attribute, text, and alt simultaneously. Regular shorthands don't need *; regular Wrap only needs to place content in the last element.📖 Summary
- Wrap with Abbreviation is Emmet's "reverse Expand" — adds wrapping to existing code
- Trigger keys: VSCode
Shift+Alt+,(comma); other editorsCtrl+Shift+AorCtrl+Alt+J - 4 wrapping modes: single-element wrapping, multi-line batch wrapping, nested wrapping, combined wrapping
- Shorthand core:
>determines "wrap position" (child vs sibling);*determines "repeat by selected line count" *without a number = auto-repeat based on selected line count;*Nexplicitly specifies count$#placeholder: lets selected content appear in multiple positions of the Wrap result (attributes, text, alt, etc.)
📝 Exercises
-
Basic (Difficulty ⭐): In your HTML file, write a standalone
<p>Hello World</p>, select it, pressShift+Alt+,to trigger Wrap, typediv.wrapper, and press Enter. Verify the expansion result is<div class="wrapper"><p>Hello World</p></div>. If incorrect, check whether you forgot the>. -
Intermediate (Difficulty ⭐⭐): In an HTML file, write 3 standalone
<li>elements (without ul). Use Wrap for batch wrapping: (a) select all 3 lines; (b) typeul.nav>and verify the output; (c) then usesection.hero>to verify multi-line wrapping (no*needed — the selection itself means "as children of ul"). Record the expansion results of 3 Wrap operations. -
Challenge (Difficulty ⭐⭐⭐): In your HTML file, write a blog post fragment (
<h1>...</h1>+<p>...</p>+<p>...</p>). Use 3 Wrap operations to transform it into a complete blog card structure: 1st Wrapheader>h1+ 2nd Wraparticle.content>(p)*+ 3rd Wrapsection.blog-post>. Record the final result of the 3 Wrap operations (should be a 3-layer nested structure) and write a "Wrap vs. Manual Wrapping" speed comparison report.