solid-js

Using Components with Buildless


I copied the buildless example from the SolidJS docs then added the simplest possible custom component to it (jsfiddle):

<!DOCTYPE html>
<html>
  <body>
    <script type="module">
      import { onCleanup, createSignal } from "https://esm.sh/solid-js@1.8.1";
      import { render } from "https://esm.sh/solid-js@1.8.1/web";
      import html from "https://esm.sh/solid-js@1.8.1/html";
      
      const Foo = () => html`<em>FOO</em>`;

      const App = () => {
        const [count, setCount] = createSignal(0);
        const timer = setInterval(() => setCount(count() + 1), 1000);
        onCleanup(() => clearInterval(timer));
        return html`<div><div>${count}</div><Foo></Foo></div>`;
      };
      
      render(App, document.body);
    </script>
  </body>
</html>

The Foo component content doesn't show. How to use custom components with buildless SolidJS?


Solution

  • Tagged template literals require slightly different syntax than JSX components. Foo in your div component should reference the component definition:

    <${Foo}><//>
    

    or

    <${Foo} />
    

    If you use a string value instead of the function itself, runtime will create an html element with a tag called 'Foo':

    <foo></foo>
    

    The reactive values should be in their function form to preserve reactivity:

    ${count}
    

    or in case you need to invoke it:

    ${() => count()}
    

    Solid uses typeof function check on the value to mark it reactive. Invoking the function will extract the value and opt out of reactivity.

    Here is how it should look with children:

    import { createSignal } from 'solid-js';
    import html from 'solid-js/html'
    import { render } from 'solid-js/web';
    
    const Foo = (props) => html`<em>FOO ${props.children}</em>`;
    
    const App = () => {
      const [count, setCount] = createSignal(0);
      const timer = setInterval(() => setCount(count() + 1), 1000);
    
      return html`<div><div>${() => count()}</div><${Foo}>Some Content<//></div>`;
    };
    
    render(() => <App />, document.body);
    

    Live Demo: https://playground.solidjs.com/anonymous/d57a0130-21f1-44cc-af2a-2492682f8c7c

    You can pass props as follows:

    <${Foo} count=${() => count()}>Some Content<//>
    

    Then you can use:

    const Foo = (props) => html`<em>Count: ${() => props.count}</em>`;
    

    Live Demo: https://playground.solidjs.com/anonymous/42ea98c4-c8a6-415c-ba37-2f119c05fd56

    We use function invocation to preserve reactivity. An alternative method would be passing the signal accessor directly:

    <${Foo} count=${count}>Some Content<//>
    

    You can read more about it: https://github.com/solidjs/solid/tree/main/packages/solid/html