solidjs / solid

A declarative, efficient, and flexible JavaScript library for building user interfaces.
https://solidjs.com
MIT License
31.66k stars 888 forks source link

[html] Unable to use a `<template>` element in `html` template #1967

Open trusktr opened 7 months ago

trusktr commented 7 months ago

Describe the bug

This causes an error:

import html from 'solid-js/html' 

html`
  <div>
    <template>
      <h1>Example</h1>
    </template>
  </div>
`

Error:

Uncaught TypeError: Cannot read properties of null (reading 'firstChild')

Your Example Website or App

https://playground.solidjs.com/anonymous/5dd52803-e570-4f6e-a72d-0ef56944996f

Steps to Reproduce the Bug or Issue

see console

Expected behavior

expect to use a <template> element like normal HTML

Screenshots or Videos

No response

Platform

Additional context

No response

ryansolid commented 7 months ago

Are you expecting dynamic expressions? Just wondering because templates walk differently... Is the expectation that walks just stop? If so dynamic inserts would break from a mismatch. I guess if it is a template it would be .content.firstChild.

femincan commented 7 months ago

I've been trying to solve this issue for the last two days but couldn't succeed.

The error comes from the lit-dom-expressions package. The package mostly uses node properties like firstChild, nextSibling, and children, but these properties are empty in the template element. It exposes all of its content to the content property.

ryansolid commented 7 months ago

@femincan exactly. It is a very different sort of element. It would require custom code generation for just that case. I don't think Solid's JSX handles it properly either. I've never bothered trying to get the transform working for them. It should be doable I think but it requires a little bit of specific work.

trusktr commented 6 months ago

In my case, I'm not trying to interpolate anything inside the <template>. But I would imagine interpolating should work. I could imagine someone could interpolate to update the template content, then stamp that out in its new shape each time using cloneNode.

In my case, I use it to write HTML code for live code demos using a <live-code> custom element (uses a <code-mirror> element under the hood), and the purpose of the <template> is so that the content is not rendered or instantiated by the browser.

For example, everything inside the <template> will become editable code with live preview:

<live-code>
  <template>
    <!-- Everything inside of here is just source code for a demo -->
    <head>
      <!-- we don't want this script to execute -->
      <script>...</script>
    </head>
    <body>
      ...
    </body>
  </template>
</live-code>

Example usage:

https://github.com/lume/lume.github.io/blob/f9d8da461260e94b076d5e6620abb73a0ce5c9d7/guide/positioning/README.md?plain=1#L28-L43

This is the result:

https://docs.lume.io/guide/positioning/

Now that I think about it, my <live-code> element currently doesn't observe changes to <template>, it only uses the initial content. But an upgrade would be for it to update the code editor if the template content changes (and those changes could be due to Solid templating updating the DOM)