Skip to content

Repository files navigation

Emmet CLI

A powerful command-line interface for Emmet abbreviation expansion, powered by the same library that VSCode uses (@vscode/emmet-helper).

Features

  • Full VSCode Emmet Support: All filters (BEM, comment, trim), wrapping, custom snippets, and configuration options
  • 15+ Languages: HTML, CSS, JSX, Vue, SCSS, LESS, Sass, Pug, HAML, Slim, and more
  • Flexible Configuration: Load custom snippets, variables, and syntax profiles from .emmet/ directory
  • Standard I/O: Read from stdin, write to stdout for easy piping and integration
  • Subcommands: expand, wrap, extract, and validate

Installation

# Install globally
npm install -g @saifulapm/emmet-cli
# Or install locally in your project
npm install --save-dev @saifulapm/emmet-cli

Development Setup

# Clone the repository
git clone https://github.com/saifulapm/emmet-cli.git
cd emmet-cli
# Install dependencies
npm install
# Build
npm run build
# Link globally for testing
npm link

Quick Start

# Expand HTML abbreviation
emmet expand "ul>li*3" --syntax html
# From stdinecho"div.container>p"| emmet expand --syntax html
# CSS abbreviation
emmet expand "m10+p5" --syntax css
# Wrap text with abbreviationecho"Hello World"| emmet wrap "div.greeting" --syntax html
# Extract abbreviation from text
emmet extract "div.test" --syntax html

Commands

emmet expand [abbreviation]

Expand Emmet abbreviation to code.

Options:

  • -s, --syntax <lang> - Language/syntax (html, css, jsx, etc.)
  • -f, --filter <filters> - Filters: bem, c, t (comma-separated)
  • -c, --config <path> - Custom config directory
  • -i, --indent <chars> - Indentation string (default: tab)
  • -t, --tab-stops - Include tab stops (default: true)
  • -n, --no-tab-stops - Disable tab stops
  • --var-<name>=<value> - Set template variables

Examples:

# Basic expansion
emmet expand "ul>li*3" --syntax html
# Output:# <ul># <li></li># <li></li># <li></li># </ul># Without tab stops
emmet expand "div.container>p" --syntax html --no-tab-stops
# CSS abbreviation
emmet expand "m10+p5" --syntax css
# Output: margin: 10px; padding: 5px;# JSX with custom attributes
emmet expand "button[onClick={handleClick}]" --syntax jsx
# Custom indentation (2 spaces)
emmet expand "ul>li*2" --syntax html --indent "" --no-tab-stops
# Or using short options:
emmet expand "ul>li*2" -s html -i "" -n
# Set template variables
emmet expand "!" --syntax html --var-lang=en --var-charset=UTF-8
# Using short options for quick commands
emmet expand "div#app>header.header" -s html -f c -n

emmet wrap <abbreviation>

Wrap text/selection with Emmet abbreviation (text from stdin).

Options:

  • -s, --syntax <lang> - Language/syntax
  • --multi-line - Each line becomes a separate item

Examples:

# Wrap single textecho"Hello World"| emmet wrap "div.greeting" --syntax html
# Output: <div class="greeting">Hello World</div># Wrap multiple linesecho -e "Item 1\nItem 2\nItem 3"| emmet wrap "ul>li*" --syntax html --multi-line
# Output:# <ul># <li>Item 1</li># <li>Item 2</li># <li>Item 3</li># </ul># Wrap with nested structureecho"Content"| emmet wrap "div.container>article" --syntax html

emmet extract [text]

Extract abbreviation from text (useful for autocomplete).

Examples:

# Extract from text
emmet extract "div.container" --syntax html
# From stdinecho"ul>li*3"| emmet extract --syntax html

emmet validate <abbreviation>

Validate Emmet abbreviation syntax.

Examples:

# Valid abbreviation
emmet validate "div.container>p*3" --syntax html
# Output: valid# Invalid abbreviation
emmet validate "div.>>>" --syntax html
# Output: invalid

Supported Languages

Markup Languages

  • html - HTML
  • xml - XML
  • xsl - XSL
  • jsx - React JSX
  • tsx - TypeScript JSX
  • vue - Vue.js templates
  • svelte - Svelte components
  • pug - Pug (Jade)
  • slim - Slim
  • haml - HAML

Stylesheet Languages

  • css - CSS
  • scss - Sass SCSS
  • sass - Sass (indented)
  • less - LESS
  • stylus - Stylus
  • sss - SugarSS

Configuration

The CLI supports loading custom configuration from multiple locations with the following priority (lowest to highest):

  1. Built-in defaults from @vscode/emmet-helper
  2. User home: ~/.emmet/snippets.json + ~/.emmet/syntaxProfiles.json + ~/.emmet/config.json
  3. Project root: .emmet/snippets.json + .emmet/syntaxProfiles.json + .emmet/config.json
  4. Custom path via --config <dir> flag
  5. CLI flags (--var-*, etc.)

Configuration Files Overview

All configuration files live in the .emmet/ directory:

  • snippets.json - Custom snippets and template variables per syntax
  • syntaxProfiles.json - Output formatting per syntax (tag case, quotes, self-closing style)
  • config.json - Advanced preferences (BEM separators, CSS units, comment triggers, etc.)

snippets.json

Define custom snippets and template variables:

{
"variables": {
"lang": "en",
"charset": "UTF-8",
"author": "Your Name"
},
"html": {
"snippets": {
"hero": "section.hero>div.container>h1{Hero Title}+p{Hero description}",
"card": "div.card>img+div.card-body>h3.card-title{Title}+p.card-text{Text}"
}
},
"css": {
"snippets": {
"fx": "display: flex;",
"fxc": "display: flex; align-items: center; justify-content: center;"
}
}
}

Usage:

emmet expand "hero" --syntax html
emmet expand "fx" --syntax css

Important: Snippets must be valid Emmet abbreviation syntax (tags, classes, IDs, nesting operators like >, +, ^, etc.). Plain text or code won't work - it will be treated as a tag name.

syntaxProfiles.json

Customize output formatting per syntax:

{
"html": {
"tag_case": "lower",
"attr_case": "lower",
"attr_quotes": "double",
"self_closing_tag": "html"
},
"jsx": {
"self_closing_tag": "xhtml"
}
}

config.json

Advanced preferences and variables:

{
"variables": {
"lang": "en",
"charset": "UTF-8"
},
"preferences": {
"css.intUnit": "rem",
"css.floatUnit": "rem",
"bem.elementSeparator": "__",
"bem.modifierSeparator": "--",
"profile.allowCompactBoolean": true
}
}

Available Preferences:

CSS Preferences:

  • css.color.short - Use short color format (#fff vs #ffffff)
  • css.intUnit - Unit for integers (default: "px")
  • css.floatUnit - Unit for floats (default: "em")
  • css.fuzzySearchMinScore - Fuzzy search threshold 0-1 (default: 0.3)
  • css.valueSeparator - Between property and value (default: ": ")
  • css.propertyEnd - After each property (default: ";")

HTML Formatting:

  • format.noIndentTags - Tags to not indent (comma-separated)
  • format.forceIndentationForTags - Force indentation for tags
  • output.inlineBreak - Inline elements before line break (default: 3)
  • output.reverseAttributes - Reverse attribute order
  • output.selfClosingStyle - "html" | "xhtml" | "xml"

Boolean Attributes:

  • profile.allowCompactBoolean - <input disabled> vs <input disabled="disabled">

Comment Filter:

  • Note: Comment filter settings use special defaults from vscode-emmet-helper
  • Only override filter.commentTrigger, filter.commentBefore, filter.commentAfter if you need custom comment templates

BEM:

  • bem.elementSeparator - Element separator (default: "__")
  • bem.modifierSeparator - Modifier separator (default: "_")

Filters

Emmet filters modify the output of abbreviations. Chain multiple filters with |:

BEM Filter (|bem)

Expands BEM (Block Element Modifier) notation:

emmet expand "ul.nav>li.nav__item*2" --syntax html --filter bem

Comment Filter (|c)

Adds HTML comments to elements with ID or class:

emmet expand "div#app>header.header+main.content" --syntax html --filter c

Output:

<divid="app"><headerclass="header"></header><!-- /.header --><mainclass="content"></main><!-- /.content --></div><!-- /#app -->

Trim Filter (|t)

Removes extra whitespace:

emmet expand "ul>li*3" --syntax html --filter t

Combined Filters

emmet expand "div.block>div.block__element" --syntax html --filter "bem,c"

Example Workflows

React Component Snippets

Create .emmet/snippets.json:

{
"jsx": {
"snippets": {
"card": "div.card>div.card-header>h3{Title}^div.card-body>p{Content}",
"modal": "div.modal>div.modal-content>div.modal-header>h2{Modal Title}^div.modal-body>p{Modal content}^div.modal-footer>button{Close}",
"form": "form>div.form-group>label{Name}+input[type=text name=username]^button[type=submit]{Submit}"
}
}
}

Usage:

emmet expand "card" --syntax jsx --no-tab-stops
# Output: <div className="card">...</div>
emmet expand "form" --syntax jsx --no-tab-stops
# Generates complete form structure with JSX syntax

Note: Emmet snippets must use Emmet abbreviation syntax (tags, classes, nesting). They cannot contain arbitrary JavaScript code.

CSS Utility Classes

Create .emmet/snippets.json:

{
"css": {
"snippets": {
"flex-center": "display: flex; align-items: center; justify-content: center;",
"abs-center": "position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"
}
}
}

Usage:

emmet expand "flex-center" --syntax css

Team Configuration

Commit .emmet/ directory to your repository:

your-project/
├── .emmet/
│ ├── snippets.json # Team snippets
│ ├── syntaxProfiles.json # Output formatting
│ └── config.json # Preferences
├── src/
└── package.json

All team members will use the same Emmet configuration!

Environment Variables

  • DEBUG_EMMET=1 - Enable debug logging
DEBUG_EMMET=1 emmet expand "div.test" --syntax html

API Usage

import{expandCommand,wrapCommand,extractCommand,validateCommand}from'@saifulapm/emmet-cli';// Expand abbreviationconsthtml=awaitexpandCommand({abbreviation: 'div.container>p*3',syntax: 'html',tabStops: false});// Wrap textconstwrapped=awaitwrapCommand({abbreviation: 'div.wrapper',text: 'Hello World',syntax: 'html'});// Extract abbreviationconstresult=awaitextractCommand({text: 'div.test',syntax: 'html'});// Validate abbreviationconstresult=awaitvalidateCommand({abbreviation: 'ul>li*3',syntax: 'html'});

License

MIT

Contributing

Contributions are welcome! Please open an issue or pull request.

Credits

Built with:

About

Powerful command-line interface for Emmet abbreviation expansion. Supports 15+ languages, custom snippets, and full VSCode Emmet compatibility.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages