Components in Vanillin are a bit like Web Components. You can:
- instantiate them with
- pass params:
<my-component param1="value" />,
- attach event listeners:
and much more.
Let's define one:
<function name="panel"> <h2>A panel</h2> <p>Hello world</p> </function>
Component definition is similar to function definition - in ECMAScript the function definition is called
Function Declaration, because it's a statement, not an expression.
name attribute is required if the function is defined as one of the elements of DOM tree. There is and exception to this though.
name it would be a component expression (
Function Expression in ECMAScript), but it would be non-idiomatic in Vanillin (in HTML) to be run as IIFE. Therefore it's allowed only if the component is defined using external template, not with inline code.
Element's name -
function - was chosen deliberately to resemble ECMAScript.
Let's use it:
You can also use
bind-component expects a string value to be passed which will refer to an environment binding name in current scope. Important note: values passed to
See an example:
In example above, Vanillin looks for
panel value inside enclosing environment.
bind-component can be useful if you want to use non-standard HTML elements - like
panel - which in some cases may be hoisted up the tree by browser and break your design.
For example, this markup:
<table> <thead> <foo></foo> </thead> </table>
will be transformed into:
<foo></foo> <table> <thead></thead> </table>
bind-component-expr is similar to
bind-component, but, as name suggests, the final name is evaluted from expression passed inside attribute name. Example:
<script> const componentName = "panel"; </script> <div bind-component="componentName"></div>
<function name="panel" title="'Untitled'" contents> <h2 bind>title</h2> <p bind>contents</p> </function>
<script> var componentsCounter = 0; </script> <p>How many components were created? <strong bind>componentsCounter</strong></p> <function name="panel" title="'Untitled'"> <script> componentsCounter = componentsCounter + 1; </script> <div bind>title</div> </function> <panel></panel> <panel title="'Panel1'"></panel> <panel title="document.title"></panel> <span bind-component="panel" title="'Run component with attribute'"></span>
<strong> will display
As a corollary:
components can be part of closure, too:
<function name="menu-item" text> <span bind>text</span> </function> <function name="menu" items=""> <menu-item for="let item of items" text="item"></menu-item> </function> <menu items="['Home', 'Contact', 'About']"></menu>
they can be nested:
<function name="menu" items=""> <function name="menu-item" text> <span bind>text</span> </function> <menu-item for="let item of items" text="item"></menu-item> </function> <menu items="['Home', 'Contact', 'About']"></menu>
scoping works properly:
<function name="outer"> <function name="inner">Hello!</function> </function> <!-- can see "Hello!" --> <outer></outer> <!-- can't see "Hello!" --> <inner></inner>
On the other hand, Vanillin components do not:
returnvalues - feasability of such mechianism is not clear, hence not implemented,
- inherit from
applyetc. support - simply not implemented so far and not clear if would be useful.
We've discussed inline HTML component definitions. Let's switch to programmatic usage.