Vim syntax highlighting for HTML embedded in JavaScript files
I am currently working on a web project where I have been using Web Components. They are a great way to create customized html elements and limit code duplication. However, this means writing a lot of HTML code inside standard JavaScript files.
The problem
For vim users, this can be a bit annoying because the syntax highlighting is not enabled by default. The HTML code is treated as a regular string:
const template = document.createElement('template')
template.innerHTML = `
<style>
.my-component {
color: red;
}
</style>
<div class="my-component">
Hello, World!
</div>
`
class MyComponent extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' })
this.shadowRoot.append(template.content.cloneNode(true))
}
}
customElements.define('my-component', MyComponent)
The solution
To fix this for vim you can simply add the following lines to your .vimrc
:
call plug#begin('~/.vim/plugged')
Plug 'inkarkat/vim-SyntaxRange'
call plug#end()
augroup SyntaxRangeHTML
autocmd!
autocmd BufRead,BufNewFile *.js silent! call SyntaxRange#Include('.*HTML.*`', '`', 'html')
autocmd BufRead,BufNewFile *.js silent! call SyntaxRange#Include('<style>', '</style>', 'css')
augroup END
I looked for a plugin that would handle web components syntax highlighting but it seems that it only exists for VSCode. So I found the next best thing, a plugin that allows a user to partially change a file’s syntax.
Breakdown
This part sources the
vim-SyntaxRange plugin using
vim-plug. After having changed your
.vimrc
file and reloaded it (using :source ~/.vimrc
), run :PlugInstall
to
actually install it. You can of course use another plugin manager or install it
manually if you prefer.
call plug#begin('~/.vim/plugged')
Plug 'inkarkat/vim-SyntaxRange'
call plug#end()
This part of the configuration will actually enable the syntax highlighting for HTML code in Web Components:
augroup SyntaxRangeHTML
autocmd!
autocmd BufRead,BufNewFile *.js silent! call SyntaxRange#Include('.*HTML.*`', '`', 'html')
autocmd BufRead,BufNewFile *.js silent! call SyntaxRange#Include('<style>', '</style>', 'css')
augroup END
The autocmd triggers when opening a .js
file and calls the
SyntaxRange#Include
function with the following parameters:
.*HTML.*`
and`
are patterns for the start and end delimiters of the HTML code.html
is the syntax group that will be applied to code between the delimiters.
Here it works if the the string HTML
is found before the backtick opening the
template string. The closing backtick is used as the end delimiter. So in the
example above the template.innerHTML = `
line will trigger the HTML syntax
highlighting.
These delimiters are specific to my use case, so you might need to adjust them
to fit your needs. However the use of the innerHTML
property is not mandatory.
With this pattern a simple /* HTML */
or /* html */
comment before the
backtick will also work.
While I was there I also added CSS syntax highlighting. This is simply triggered
by the <style>
tag and ended by the </style>
closing tag.
Note
The !silent
flag is used to prevent the plugin from displaying error messages
when the SyntaxRange#Include
function is called. A variable is undefined in
the script but it does not seem to affect the plugin’s functionality.
Conclusion
This is an acceptable workaround for the lack of built-in support for HTML syntax highlighting in Web Components. It is not perfect but it gets the job done. I hope this helps you as much as it helped me. Happy coding!