lit is more code than my own framework, so that was not a contender.
Second I tried Declarative Shadow DOM. This was actually great. The problem I ran into with it was that to my surprise Declarative Shadow DOM works without Javascript. That does make sense I guess, but it means that combined with sparse support you have to support a matrix of JS, no JS, support, and no support for styling. I may write more about that at some point, because I will likely come back to Declarative Shadow DOM for limited things. For instance the code blocks on this site perhaps where it makes sense to do the syntax highlighting on the server, but I also want some interactivity like toggling word wrapping which I had in this site's previous iteration and have removed for this one.
So eventually I settled on the idea of using JSX. I should say right up front that I have never been a fan of JSX. It's seemed unnecessary. We have template literals after all, which have the advantage of being able to be cached where as JSX is just function calls on every render. But JSX has a few advantages. First support for them is built into everything basically: Babel, and more importantly for me, SWC. Second, code editor support is great. It means I do not have to install a plugin in VS Code just for syntax highlighting. A possible third advantage to JSX is that I work with React at work now, so staying in that realm for hobby stuff helps prevent context switching.
OK so how do we use JSX with Web Components? There are really just two steps with an optional third.
h
function.Fragment
function if you use fragments.For step 1, if you are using Babel you can use their JSX plugin along with setting runtime to classic
and pragma to h
and pragmaFrag to Fragment
.
And here is an example of h
and Fragment
. You just need to be sure to import them or make sure they are defined wherever you use JSX.
function h(tag, props, ...children) { children = children.flat(Infinity); if (typeof tag === "function") return tag({...props, children}); let node = document.createElement(tag); for (let [key, val] of Object.entries(props ?? {})) { if (key.startsWith("on")) { node.addEventListener(key.substring(2).toLowerCase(), ...[].concat(val)); } else { node[key] = val } } node.append(...children); return node; } function Fragment({children}) { return children; }
My dream is the have a html tagged template function built into browsers, but in the meantime as long as I'm using Babel, or similar, JSX is a pretty good substitute