Components

Overview

TODO

Defining a Component

TODO: <template hyper-component="tag-name">

Template Body

TODO: ${} interpolation, #for, #if

Slots

TODO: default slots, named slots

The attrs Proxy

TODO: attribute evaluation in parent scope, bidirectional binding

Reactive Rendering

TODO: automatic re-render via morph when dependencies change

DOM Isolation

TODO: dom-scope="isolated", ^var scoping boundaries

Examples

Filterable List Component

<template hyper-component="filter-list" _="set ^list to attrs.items">
  <input type="text" placeholder="Search..."
         _="on input
              hide #no-match
              show <li:not(#no-match)/> in closest <filter-list/>
                when its textContent contains my value
                ignoring case
              show #no-match when the result is empty" />
  <ul>
  #for item in ^list
    <li><a href="${item.url}">${item.name}</a></li>
  #end
    <li id="no-match" style="display:none; color:var(--text-muted)">No results</li>
  </ul>
</template>

Usage:

<filter-list items="[{name: 'Macintosh 128K', url: 'https://en.wikipedia.org/wiki/Macintosh_128K'},
                      {name: 'Macintosh Plus', url: 'https://en.wikipedia.org/wiki/Macintosh_Plus'},
                      ...]">
</filter-list>

Demo:

Reactive Filterable List

The same component using reactive rendering instead of show/hide. The #if inside #for filters at render time: when ^query changes, the template re-renders and the result is morphed in. If no matches are found it will show a "No Results" item.

<template hyper-component="reactive-filter-list"
        _="set ^list to attrs.items
           set ^query to ''">
  <input type="text" placeholder="Search..." _="bind me to ^query" />
  <ul>
    #for item in ^list where its name contains the ^query ignoring case
      <li><a href="${unescaped item.url}">${item.name}</a></li>
    #else
      <li>No Results</li>
    #end
  </ul>
</template>

Demo: