Emmet: Custom Attributes `[attr=val]` and Numbering `$`

After the first 7 lessons, you can already write HTML with arbitrary nesting, arbitrary attributes, and arbitrary repetition using Emmet. But two "factory-style" scenarios remain unsolved—"10 inputs each with a different name" and "100 table rows with auto-incrementing numbers." These two scenarios are solved by custom attributes [attr=val] and numbering $ respectively—the final two puzzle pieces for Emmet's batch-generation capabilities.

1. What You Will Learn


2. A Frontend Developer's Real Story

(1) The Pain: Too Many Form Fields + Too Many Table Rows

Alice received a task to build a combined login + registration form with 5 inputs (username, email, password, confirm password, remember me) and 1 submit button. After writing one form, she realized that all the input names looked nearly identical—name="user", name="email", name="pwd", and so on—each one had to be typed manually.

Even worse was the "Terms of Service" table on the registration page: 100 rows of terms, each row a tr, with column 1 being a sequence number (1–100) and column 2 being the term text. Alice tried hand-writing: tr>td{1}+td{Term 1}, tr>td{2}+td{Term 2}, ... by row 30 she gave up. Just writing 30 similar "tr + 2 td" lines took her 30 minutes.

Finally, after writing all the fields, Alice also needed to add HTML5 attributes like aria-label="Username input" and data-validate="email" to the inputs—each attribute required checking specs, typing equals signs, and adding quotes. 30 input lines ballooned into 90 lines of HTML.

(2) How [attr=val] and $ Solve It

Emmet provides two complementary mechanisms to solve Alice's problems:

Custom attributes [attr=val]: Write any attribute inside square brackets, presented directly like HTML—Alice can write each input as input[name=user type=text] in one line, and aria and data-* attributes can similarly go inside the brackets.

Numbering $: Makes the class, id, and attribute values of repeated elements auto-increment. The 100 terms' sequence numbers can be generated with td.item$@100*100 in one line (starting from 100, descending), and the term text can be filled with {text} (covered in Lesson 09).

Alice rewrote the entire form in one line of Emmet:

TEXT 📖 参照専用
form>(input[name=user type=text placeholder="Username"])+(input[type=email name=email])+(input[type=password name=pwd])+(input[type=password name=pwd-confirm])+(label>input[type=checkbox name=remember]+{Remember me})+(button[type=submit]{Login})

And the 100-row terms table:

TEXT 📖 参照専用
(table>(tr>td{item $}*3)*5)

After verifying, Alice exclaimed: "5 input fields went from 25 hand-written lines to 1 line, and the 100-row terms table went from 350 lines to 1 line. Emmet's efficiency boost in form and table scenarios is 30x or more."

(3) Benefits

[attr=val] and $ are Emmet's core operators for handling "repetition + factory-style" scenarios. The former lets you cover all HTML5 attributes in one line of abbreviation, while the latter makes sequence numbers run automatically. After this lesson, Alice can write a 5-field form in 12 seconds and a 100-row table in 10 seconds. This lesson also marks the conclusion of Phase 2—the remaining 9 lessons will cover CSS shorthand and editor Actions.


3. Custom Attributes [attr=val]: HTML5 Attributes in Square Brackets

[attr=val] is Emmet's syntax for adding arbitrary attributes to a tag. Content written inside square brackets becomes raw HTML attributes—whether standard HTML5 attributes (colspan, type, placeholder), newer HTML5 attributes (data-*, aria-*), or custom attributes.

(1) Shorthand Rules

Abbreviation Expansion Notes
td[title="Hello"] <td title="Hello"></td> Single attribute with double quotes
td[colspan=3] <td colspan="3"></td> Single attribute without quotes (OK when value has no spaces)
td[title colspan=3] <td title="" colspan="3"></td> Abbreviated form (valueless attributes)
input[type=text name=user] <input type="text" name="user"> Multiple attributes separated by spaces
a[href="#" data-id=$] <a href="#" data-id="1"></a> data-* attribute with numbering placeholder

Tip: The [attr] valueless form (e.g., [disabled]) generates attr=""—the value is an empty string. If you want a boolean attribute (e.g., <input disabled>), Emmet won't automatically strip the value; you'll need to edit it manually. However, most modern HTML standard attributes support the value form, keeping things consistent.

Key Point: The content inside square brackets is parsed entirely according to HTML5 attribute syntax—values can use single quotes, double quotes, or no quotes (when there are no spaces); multiple attributes are separated by spaces. Note: here, spaces are valid delimiters, unlike Emmet's own "space = stop character" rule. Square brackets form a "closed" context.


4. Numbering $: The Auto-Incrementing Placeholder

$ is Emmet's numbering placeholder—write $ in a class, id, attribute value, or even text position, pair it with *N repetition, and it is automatically replaced with the current sequence number (default starting from 1).

(1) Where $ Can Be Used

Location Abbreviation Expansion (*3)
Inside class li.item$*3 <li class="item1">, <li class="item2">, <li class="item3">
Inside id div#user$*3 <div id="user1"> ...
Inside attribute value a[data-id=$]*3 <a data-id="1"> ...
Inside text ({}) a{Link $}*3 <a href="">Link 1</a> ... (covered in Lesson 09)

(2) Multi-Digit Zero-Padding $$$

Chaining multiple $ characters produces multi-digit zero-padding:

$ Count Expanded Form Use Case
item$ item1 item2 item3 Lists, menus
item$$ item01 item02 item03 Small lists
item$$$ item001 item002 item003 Table rows, cards
item$$$$ item0001 ... Rare (thousands of rows)

(3) Reverse $- and Starting Value $@N

By default, numbering starts from 1 ascending. Use @- for descending, and @N to start from N:

Modifier Meaning Example (*3)
$ (default) Ascending, from 1 1, 2, 3
$- or @- Descending (max → 1) 3, 2, 1
$@3 Ascending, from 3 3, 4, 5
$-3 or @-3 Descending, from 3 backwards 3, 2, 1

Key Point: In $@N, N is the starting value, not the ending value. This is commonly used for scenarios like "starting from a specific number" (e.g., pagination page numbers, product SKU codes, version numbers).


5. Practical Examples

The following 5 examples cover all core combinations of [attr] and $—from single attributes to multiple attributes, from basic numbering to multi-digit zero-padding, from reverse to table scenarios.

▶ Example: Basic Attributes td[title="Hello" colspan=3] (Difficulty ⭐)

Add both title and colspan attributes to a td. This is one of the most classic attribute combinations in HTML tables.

Abbreviation:

HTML
td[title="Hello" colspan=3]

Expansion:

HTML
<td title="Hello" colspan="3"></td>

Output:

TEXT 📖 参照専用
Double quotes wrap the title containing a space ("Hello"), and no quotes wrap the spaceless value (3). Emmet automatically adds quotes to all attributes regardless of whether you included them in the abbreviation. Multiple attributes are separated by spaces, which is different from Emmet's own "space = stop character" rule—spaces have special meaning inside square brackets. colspan=3 indicates the cell spans 3 columns horizontally.

▶ Example: Input Attributes input[type=text name=user placeholder=Username] (Difficulty ⭐)

Add type, name, and placeholder attributes to an input in one go. Input is one of the most "attribute-dense" tags in HTML.

Abbreviation:

HTML
input[type=text name=user placeholder=Username]

Expansion:

HTML
<input type="text" name="user" placeholder="Username">

Output:

TEXT 📖 参照専用
Three attributes completed in one abbreviation. Note: Emmet intelligently defaults input to type="text" (even if you omit type), so writing just `input[name=user placeholder=Username]` still produces type="text". If you want type="password" or type="email", you must write it explicitly. Three chained attributes are the highest-frequency shorthand in form scenarios.

▶ Example: Single $ Numbering ul>li.item$*5 (Difficulty ⭐)

Five li elements, each with a class that auto-increments from 1 to 5—the premier example from Emmet's official documentation.

Abbreviation:

HTML
ul>li.item$*5

Expansion:

HTML
<ul>
  <li class="item1"></li>
  <li class="item2"></li>
  <li class="item3"></li>
  <li class="item4"></li>
  <li class="item5"></li>
</ul>

Output:

TEXT 📖 参照専用
Five li elements with classes item1, item2, item3, item4, item5. This is Emmet's standard pattern for uniquely numbered items (item + number). If the class name doesn't need a numeric part, simply write .item (without $), and all li elements share the same class.

▶ Example: Multi-Digit $$$ Zero-Padding ul>li.item$$$*5 (Difficulty ⭐)

Use 3 $ characters to auto-zero-pad numbering to 3 digits.

Abbreviation:

HTML
ul>li.item$$$*5

Expansion:

HTML
<ul>
  <li class="item001"></li>
  <li class="item002"></li>
  <li class="item003"></li>
  <li class="item004"></li>
  <li class="item005"></li>
</ul>

Output:

TEXT 📖 参照専用

QUERY LENGTH LIMIT EXCEEDED. MAX ALLOWED QUERY : 500 CHARS

▶ Example: Table + Numbering (table>(tr>td{item $})*3) (Difficulty ⭐⭐)

Grouping + repetition + text content—a "numbered list" of 3 rows × 1 column, using grouping so that td follows each tr's repetition.

Abbreviation:

HTML
(table>(tr>td{item $})*3)

Expansion:

HTML
<table>
  <tr>
    <td>item 1</td>
  </tr>
  <tr>
    <td>item 2</td>
  </tr>
  <tr>
    <td>item 3</td>
  </tr>
</table>

Output:

TEXT 📖 参照専用

QUERY LENGTH LIMIT EXCEEDED. MAX ALLOWED QUERY : 500 CHARS


6. Complete Example: Form Fieldset + Multi-Digit Zero-Padded IDs

Combine [attr] and $—a registration form with 5 input fields, each field having a 3-digit zero-padded id.

▶ Example: Registration Form + 3-Digit IDs (Difficulty ⭐⭐)

Abbreviation:

HTML
form#register>(fieldset>legend{Account Info})+(input#field-001.form-control[type=text name=user])+(input#field-002.form-control[type=email name=email])+(input#field-003.form-control[type=password name=pwd])+(label>input#field-004[type=checkbox name=news]+{Subscribe to newsletter})+(button#btn-100.btn.btn-primary[type=submit]{Register})

Expansion:

HTML
<form id="register">
  <fieldset>
    <legend>Account Info</legend>
  </fieldset>
  <input id="field-001" class="form-control" type="text" name="user">
  <input id="field-002" class="form-control" type="email" name="email">
  <input id="field-003" class="form-control" type="password" name="pwd">
  <label>
    <input id="field-004" type="checkbox" name="news">
    Subscribe to newsletter
  </label>
  <button id="btn-100" class="btn btn-primary" type="submit">Register</button>
</form>

Output:

TEXT 📖 参照専用

QUERY LENGTH LIMIT EXCEEDED. MAX ALLOWED QUERY : 500 CHARS


Try It Yourself: Type td[title="Hello world!" colspan=3] into the Emmet Official Cheat Sheet to see the real-time expansion.


❓ よくある質問

Q What is the difference between [attr] and [attr=]?
A [attr] is shorthand equivalent to [attr=""] (empty string value), expanding to <tag attr="">; [attr=] explicitly assigns an empty string, expanding to the same <tag attr="">. Both produce identical results. In HTML semantics, a valueless attribute (e.g., disabled="") behaves the same as a bare attribute name (disabled)—but Emmet defaults to generating the value form, so you may need to trim it manually.
Q Can [data-id=$] work without *?
A Yes, but without * repetition, $ defaults to 1. So a[data-id=$] expands to <a data-id="1"></a>—which is usually not what you want. If you just want a data ID without numbering, write a[data-id=user] with the actual value.
Q Which is correct, @- or $-?
A Emmet's official documentation supports both forms: @N means start from N, @- means descending. The combined form $-3 is equivalent to @-3—both mean descending starting from 3. Using the @ prefixed form ($@3, @3, @-3) is recommended for clarity and compatibility.

📖 まとめ


📝 練習問題

  1. Basic (Difficulty ⭐): Write one-line Emmet abbreviations that expand to: (a) an a tag with href="#", class="link", data-id="$" (note: $ without * defaults to 1); (b) a td with title="Cell", colspan=2, rowspan=3; (c) a ul>li*5, each li with a class of row-$ (single-digit numbering).
  2. Intermediate (Difficulty ⭐⭐): Write a 5-row × 4-column "grade sheet" with the first row as a header (th) and rows 2–5 as data (td), with data cell ids using 3-digit zero-padding (cell-001 through cell-020). Write it all in one Emmet line and explain why $ can be used for ids but class wouldn't work the same way.
  3. Challenge (Difficulty ⭐⭐⭐): Write a 100-row "Terms of Service table" with a 3-column structure: (a) a sequence number column using td.item$@100*100 for reverse numbering (from 100 down to 1); (b) a title column using {Term $} text content (text content covered in Lesson 09); (c) a content column left empty for now. Write it all in one Emmet line, verify the expansion, and compare the time difference between hand-writing 100 rows vs. one line of Emmet.
Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%