Skip to content
| Marketplace
Sign in
Visual Studio Code>Programming Languages>CompelemNew to Visual Studio Code? Get it now.
Compelem

Compelem

holyhigh2

|
2 installs
| (0) | Free
Syntax highlight, IntelliSense, snippets, diagnostics, and navigation support for the compelem framework's h`` template rendering.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Compelem VSCode Extension

A VS Code extension that provides rich editing support for the compelem component framework, especially for the HTML-style markup written inside the `h`...` tag templates of a component's render() function.

Features

1. Syntax Highlighting

  • The HTML text inside `h`...` functions is highlighted.
  • The CSS text inside `css`...` template functions is highlighted.
  • All compelem directive functions (show / ifTrue / ifElse / forEach / when / slot / html / classes / styles / model / bind ...) have individually configurable colors.
  • When the cursor is on a tag, the matching opening/closing tag name is highlighted — including tags that live inside ${ifElse(...)} / ${forEach(...)} / ${when(...)} branches, where the pair is resolved inside that branch instead of against the outer <template>.
  • In a .ce file, the <script> section is tokenized as source.ts, so it matches the equivalent .ts file token for token — decorators (@state, @tag, …) are colored the same way, and Ctrl+/ inserts a // line comment instead of an HTML comment.
  • In a .ce file, markup produced by a directive branch — the () => h`...` inside ${ifElse(...)} / ${forEach(...)} / ${when(...)} — is highlighted as HTML exactly like the markup that sits directly in <template>, at any nesting depth. The ${...} parts around it stay TypeScript.
  • Code folding:
    • paired HTML tags inside `h`...` templates (.ts / .tsx) and inside the <template> body of a .ce SFC;
    • in .ce files, the h`...` bodies nested inside ${...} directive branches fold too, not just the tags that sit directly in <template>;
    • in .ce files only: every top-level section tag (<template> / <script> / <style> / <cssvar>) and every multi-line { ... } block inside <script> and <style>. Braces inside strings, comments, template-literal interpolations and regular expressions are ignored.
    • Toggle with compelem.folding.enabled (on by default).

2. Formatting

  • Right-click formatting of the HTML markup template inside `h`...` functions is supported.
  • Long tags are broken into one attribute per line; short elements (e.g. <span>Hello</span>) stay on a single line.
  • When you want to keep the built-in TypeScript formatter as the default document formatter, you can use the Compelem: Format h... templates` command.
  • The number of indentation spaces can be set via compelem.format.indentSize (the default 0 means following the editor's tabSize — the very number the status bar shows as Spaces: N). A positive value overrides that for .ce files, so changing the status bar's Spaces no longer affects them; the extension says so once in the status bar when the two disagree.
  • In .ce files the <script> / <style> / <cssvar> bodies are formatted with VS Code's own TypeScript / CSS formatters and indented one level below their section tag, matching <template>. Non-CSS <style> bodies (e.g. lang="scss") are only re-indented — never handed to the CSS formatter, which would rewrite their nesting.
  • Set compelem.format.embeddedIndent to flush to keep those bodies at column 0 instead (the Vue convention). Prefer it when a <script> contains multi-line template literals, whose leading whitespace is part of the string. compelem.format.embeddedSections: false disables the pass entirely.

3. IntelliSense & Completion

  • Typing <l- (or a PascalCase prefix) inside `h`...` functions lists the components registered in the workspace.
  • Typing . on a component tag lists the component's props — including the properties inherited via extends (e.g. color / size / disabled from a base class) — and shows their type, default value, and @attrs documentation.
  • In any tag's attribute area, global HTML attributes are suggested: class / style / name / id / title / hidden / tabindex / role / aria-label / aria-hidden / lang / dir / slot and data-* (accepting inserts class="" with the caret between the quotes).
  • Typing @ on a tag suggests event names: native tags get their tag-specific events (<slot> → slotchange, <input> → input / change, <form> → submit, ...), component tags additionally get their @emits events. Only the event name is inserted, so modifiers can follow.
  • Typing . after an event suggests event modifiers (self / stop / prevent / once / capture / passive / left / right / middle / ctrl / alt / shift / meta / esc / debounce / throttle), chainable (@click.stop.self) with used modifiers de-duplicated.
  • Typing = after an event inserts the handler reference (@click= → @click="${this.onClick}", modifiers never leak into the name).
  • Typing an opening tag like <div> automatically inserts </div> and moves the cursor inside the element.
  • Typing <xx propname= on a component tag automatically inserts "${this.value}".
  • Typing show / bind / classes / styles / model / html on any tag suggests a tag-directive snippet such as ${show(this.visible)}; inside ${ ... }, text directives (forEach / when / ifTrue / ifElse / slot) are suggested instead.
  • Typing @ outside templates suggests decorators: @computed / @watch / @query / @tag / @prop / @csscope, with auto-completion on acceptance.
  • In .ce files, completion inside <script>, inside a <template> expression and inside a <cssvar> value is answered by the real TypeScript language service (request forwarding), so types, methods and inherited members are offered there — the regex-based this. list is only a fallback for the cases the bridge cannot serve.
  • .ce section tags (<style ...>) complete both attribute names and values. lang offers exactly css / scss / sass (dart-sass compiles the non-CSS ones at build time; any other value is a build error), and scope offers inner / host / global as a whitespace-separated list (scope="host inner" — only the token under the caret is replaced and already-written values are skipped). <template> / <script> / <cssvar> take no attributes and get no suggestions. A section tag must start at column 0, matching the parser's own ^<(template|script|style|cssvar) rule, so an indented <style> is treated as a plain element inside the template and gets no section attributes. Values are reachable two ways: (1) accepting lang / scope inserts a choice snippet, so the accepted values pop up right at the caret; (2) inside the quotes, Ctrl+Space. Attribute values live inside a string, and VS Code's default editor.quickSuggestions.strings is "off" — typing inside a string never requests completion. This extension registers " and ' as trigger characters, so the list also appears the moment the opening quote is typed.

4. Snippets

  • render → generates a render() that returns an `h`...` function template containing a root <div>.
  • @watch → generates an empty @watch(...) method.
  • @computed → generates an empty @computed getter.
  • @csscope → generates an @csscope(Csscope.INNER) static getter template.

5. Diagnostics

  • The ref attribute must be an interpolation of a createRef member, e.g. ref="${this.xxRef}".
  • The .xx directive attribute is allowed on any component tag — ce-xx elements, dashed custom-element names (e.g. ce-xx, a-b-c), or PascalCase components (e.g. <l-input .value="${this.xx}">); .xx on <slot> is valid.
  • The same directive (show / bind / classes ...) may only appear once per element.
  • Decorator placement: @csscope only on static getters, @watch only on methods, @computed only on non-static getters, @emits / @tag only on classes.
  • Event names passed to this.emit(...) must be declared in the class' @emits decorator (ancestors are merged along the extends chain; classes without any @emits on the chain are not checked).
  • @event="${this.onXxx}" values must be function references (method, arrow-function field, or function field) — missing members and non-function members are flagged.
  • Shape rules for the <script> section (a .ce with a <template> must declare exactly one component class): E-CE-CLASS-COUNT (none, or more than one), E-CE-CLASS-EXPORT (not exported), E-CE-CLASS-BASE (no extends, or a base that cannot be traced to CompElem — extends HTMLElement, for instance). Reported with source compelem-sfc, underlined on class Name. The rules are the build's own implementation (vite/sfc/src/script-rules.ts compiled into out/vendor/), so the editor and vite build cannot disagree. Section detection follows the build too: a section tag must start at column 0, so an indented or single-line <script> does not exist as far as the build is concerned and is reported as "no component class". A .ce without a <template> is a plain module and is not checked.
  • TypeScript errors in the <script> section are produced by a private TS language service and surface with source ts (e.g. TS2322 type mismatch, TS2300 duplicate identifier). The canonical case: writing class X twice in one <script> reports TS2300 Duplicate identifier on both declarations. That is editor-side only; the build reports The symbol "X" has already been declared from esbuild's TS→JS lowering step, with the .ce line number.

6. Navigation & hover

  • Hold Ctrl and click a component tag (l-xx / PascalCase) to jump to its @tag class definition.
  • Hold Ctrl and click a this.xxx reference to jump to that member's declaration.
  • Hold Ctrl and click a CSS class to find its .class selector: first in the css / styleSheet / insertStyleSheet template literals of the same file, then in its <style> section, and finally across **/*.{scss,css,less,ce} (other .ce components included).
  • In .ce files, three sections are forwarded to VS Code's built-in TypeScript language service: the <script> section, the expressions inside <template> (${...} / {...}), and the value expressions of every <cssvar> entry (accentColor: this.count > 2 ? … : …). Imported classes, class members and inherited members therefore resolve exactly — a target in another file jumps there as-is, and a target inside the component class is mapped back into this file's <script> section. Markup in <template> (e.g. class="...") is not JS and uses the CSS class lookup above, and so is a <cssvar> key (only its value is an expression).
  • Hovering reuses the same three sections: hovering a symbol shows the same signature and documentation TypeScript would show in a .ts file. Markup gets no tooltip on purpose — there is no regex fallback, a guessed tooltip being worse than none. (Hovering the @ of a decorator shows nothing in .ce and in .ts alike: TypeScript answers for identifiers, not punctuation.)
  • There is no workspace symbol search fallback — only the navigations above.

7. HTML comment toggling

Inside an h\`` template, Ctrl+/ normally inserts a JS line comment (//). This extension already binds Ctrl+/ (Cmd+/ on macOS) to compelem.toggleComment and Ctrl+Shift+/ (Cmd+Shift+/ on macOS) to compelem.toggleBlockComment (TypeScript / TypeScript React files only), toggling HTML comments instead — works out of the box. To override:

{
  "key": "ctrl+/",
  "command": "compelem.toggleComment",
  "when": "editorTextFocus && (editorLangId == typescript || editorLangId == typescriptreact)"
}
  • Line comment (Ctrl+/): with no selection, the caret's line is wrapped as <!-- ... --> (press again to unwrap). With a selection, each covered line is wrapped individually (indentation kept); already-commented lines are unwrapped.
  • Block comment (Ctrl+Shift+/): the whole selection is wrapped as <!-- ... --> (multi-line selections wrap across lines; press again to unwrap). With no selection, an empty <!-- --> is inserted.
  • Code outside templates keeps VS Code's native // / /* */ behavior.

License

Copyright (c) 2026 holyhigh2

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
  • Your Privacy Choices
  • Consumer Health Privacy
© 2026 Microsoft