Rendering For rendering, Thunderous exports a tagged template literal function called html``. This doesn't create a virtual DOM, but instead it directly converts an HTML string into a native DocumentFragment that can be appended to the DOM. Additionally, it enables template binding with event listeners and signals. Note that Thunderous does not sanitize the input of the html`` function. It is up to the developer to ensure that the input is safe to render. Please use a package like DOMPurify or similar to sanitize any dangerous input. It's important to remember that Thunderous will only run the component function once, when the custom element gets upgraded. This is different from other libraries that re-render the component on every state change. Instead, Thunderous relies on signals to make fine-grained updates to the DOM when the state changes, but more on that later. For conditionals, you can easily render nested templates with the html`` function. import { customElement, html } from 'thunderous'; const MyElement = customElement(() => { const cond = true; return html` <p> ${cond ? html`<span>True</span>` : html`<span>False</span>`} </p> `; }); Short-circuit evaluation is not recommended because false values may be rendered as text. Ternaries are generally a better choice for conditionals, as they provide more explicit control over the rendered output. That said, null or undefined will render nothing. For loops, you can map an array to a list of DocumentFragment objects. Each element should have a unique key attribute to help Thunderous keep track of the items in the list. import { customElement, html } from 'thunderous'; const MyElement = customElement(() => { const list = [{ id: 1, text: 'Item 1' }, { id: 2, text: 'Item 2' }]; return html` <ul> ${list.map((item) => html`<li key="${item.id}">${item.text}</li>`)} </ul> `; }); To render a reactive template, you can use derived() signals. This will hand off the signal to html``, which will then update the DOM when the signals change. For more information on signals, see the signals overview and derived signals documentation. import { customElement, html, derived, createSignal } from 'thunderous'; const MyElement = customElement(() => { const [cond, setCond] = createSignal(true); const [list, setList] = createSignal([{ id: 1, text: 'Item 1' }, { id: 2, text: 'Item 2' }]); return html` <p> ${derived(() => cond() ? html`<span>True</span>` : html`<span>False</span>`)} </p> <ul> ${derived(() => list().map((item) => html`<li key="${item.id}">${item.text}</li>`))} </ul> `; }); In the same way, you can use derived() to render reactive attribute values. import { customElement, html, derived, createSignal } from 'thunderous'; const MyElement = customElement(() => { const [cond, setCond] = createSignal(true); return html` <button class="primary ${derived(() => cond() ? 'primary--active' : '')}"> Click me </button> `; }); // alternatively, for a cleaner template... const MyElement2 = customElement(() => { const [cond, setCond] = createSignal(true); const activeClass = derived(() => cond() ? 'primary--active' : ''); return html` <button class="primary ${activeClass}"> Click me </button> `; });