Expression in text

You can bind JavaScript expression in html-text, you can use 3 types of quotes: '', "", ``.

<div>
    {name}
    {getValue('title')}
    {a} + {b} = {a + b}
    {'text with "quotes"' + `123`}
    {`js template ${variable}`}
</div>

Bindings

Reference

You can get reference to element/component using #ref and save it to a variable.

<script>
    let ref;
    let component;
</script>

<input #ref />
<Component #component />

1-way binding

For binding to attributes and properties you can write attribute={value}, if attribute and variable names the same you can use shortcut {attribute}, for binding you can use JavaScript expression.

<input value="{value}" />
<input value={value} />
<input {value} />
<button disabled={!clickable}>Click</button>

Also you can spread an object to attributes.

<script>
    let props = {
        value: 'Hello',
        title: 'Some title'
    };
</script>

<input {...props} />

2-way binding

For 2-way binding you can use bind:value={value} or shortcut :value={value}, when property name the same as variable name you can omit it, e.g. :value

<script>
    let name = '';
    let checked = false;
</script>
<input type="text" :value={name} />
<input type="checkbox" :checked />

Class and Style

To set class and style you can use class:className={condition}, style:styleName={value}.

<div class:blue={value} class:red={!value}>by class name</div>
<div class="{value?'red':'blue'}">attribute class</div>
<b style="color: {value?'green':'red'};">style as string</b>
<b style:color={value}>Style as prop</b>

<style>
    .blue {};
    .red {};
</style>

Actions

You can run some JavaScript code on element, use:action={param} or shortcut *action={param}, without arguments it looks like *action.

Also you can run some JavaScript code where $element is available - *{$element.focus()}.

<script>
    function draw(element) {
        ...
    }
</script>
<div *draw></div>
<input *{$element.focus()} />

If you need more control you can pass arguments and subscribe for updates and destroy event.

<script>
    function draw(element, a, b) {
        ...
        return {
            update: (a, b) => {},
            destroy: () => {}
        }
    }
</script>
<div *draw={a, b}></div>

Events

To listen events you can use on:eventName={expression} or shortcut @eventName={expression}.

For expression you can use function name @click={handler} or @click:handler, function declaration @click={(e) => handler(e)} or js-expression @click={handler($event)}.

<script>
    const handler = (event) => {};
</script>
<button @click:handler>Click</button>
<button @click={handler}>Click</button>
<button @click={(e) => handler(e)}>Click</button>
<button @click={handler($event, $element)}>Click</button>

Also you can use modificators for elements: enter, escape, preventDefault.

<input type="text" @keyup|enter:handler />

Also you can forward events to a parent component, @eventName to forward one type of event, @@ to forward all events from current element, the same works for components.

<button @click>Click</button>
<input type="text" @@ />
<Component @click />

Control blocks

#if-else

Block of template can be rendered by condition.

{#if condition}
    One content
{:else}
    Another content
{/if}

#each

Iterating over list.

<ul>
    {#each items as item}
        <li>{item.name}</li>
    {/each}
</ul>

Possible options:

{#each items as item}...{/each}
{#each items as item, index}...{/each}
{#each items as {id, name, key1, key2} }...{/each}
{#each items as item, index (item.id)}...{/each}
{#each items as item, index (index)}...{/each}
{#each number as value}...{/each}

#fragment

You can declare some fragment to reuse it a few times other places. Also it can be declared anywhere, e.g. inside of the #each, so it will have all scoped variables.

<div>
    {#fragment:button text}
        <div class="col-sm-6 smallpad">
            <button @click type="button" class="btn">{text}</button>
        </div>
    {/fragment}

    <fragment:button text='Left' @click:left />
    <fragment:button text='Right' @click:right />
</div>


Also you can call it recursively.

<script>
    let tree = [{
        name: 'OS',
        children: [{
            name: 'Linux',
            children: [{name: 'Ubuntu'}, {name: 'Debian'}, {name: 'RedHat'}]
        }, {
            name: 'MacOS X'
        }]
    }];

    const click = (name) => {console.log(name)};
</script>

<fragment:draw list={tree}>

{#fragment:draw list}
    <ul>
        {#each list as it}
        <li @click|stopPropagation={click(it.name)}>
            {it.name}
            {#if it.children}
                <fragment:draw list={it.children} />
            {/if}
        </li>
        {/each}
    </ul>
{/fragment}

#await

You can await a promise to display placeholder etc.

<div>
{#await promise}
    Loading...
{:then value}
    Data: {value}
{:catch error}
    Loading error: {error}
{/await}
</div>

Possible options:

{#await expression}...{:then name}...{:catch name}...{/await}
{#await expression}...{:then name}...{/await}
{#await expression then name}...{/await}

@html

To render some HTML, you can use {@html expression}.

<div>
    {@html post.content}
</div>

Components

Structure

A component can have script block, style block and rest content becomes a template

<script>
    ...
</script>

... content ...

<style>
    ...
</style>

You can import a component import Component from './Component.html', and use it in template as <Component />, a component should start with capital letter.

<script>
    import Component from './Component.html';
</script>

<Component />

Properties and attributes

You can pass some arguments into a component, it's a 1-way binding.

Also you can spread an object to pass all values as arguments.

<Component value={expression} {name} {...obj} />

You can use keyword export to mark a variable as property, so it will receive a value from parent component and will be updated on changes.

A parent can pass more arguments than number of props in a component, so all arguments will be available in $props, and all arguments which are not property are in $attributes.

<script>
    export let name = 'default';

    $props
    $attributes
</script>

<input {...$props} />
<input {...$attributes} />

2-way binding

Syntax for 2-way binding is the same as for elements.

<Component :value={variable} />

Events

It's possible to listen an event, forward an event and forward all events. Syntax for events is the same as for elements.

<Component @click:handler />

Also you can emit an custom event, for this you can use a built function $emit(eventName, details).

<script>
    $emit('myevent', 'info');
</script>

Slots

You can pass slots to a child component. To pass a default slot:

<Child>
  Some content
</Child>

<!-- Child.html -->
<slot>No content</slot>

To pass named slots:

<Child>
    {#slot:title}
        Some title
    {/slot}

    Some content

    {#slot:footer}
        Some footer
    {/slot}
</Child>

<!-- Child.html -->

<slot />
<slot>No content</slot>
<slot:title>No title</slot>
<slot:footer>No title</slot> or <slot:footer>No title</slot:footer>

A child component can pass a property to parent slot:

<Child>
    {#slot prop}
        Some content {prop.value} {parentVar}
    {/slot}
</Child>

<!-- Child.html -->

{#each items as item}
    <slot prop={item}>No content {childVar}</slot>
{/each}

Dynamic component

Dynamic component let you to attach a component from variable/expression.

<script>
    import Music from './Music.xht';
    import Movie from './Movie.xht';

    let comp, x;

    function toggle() {
        comp = comp == Music ? Movie : Music;
        x ^= 1;
    }
</script>

<component:comp />
<component:{x ? Music : Movie} />

<button @click:toggle>Switch</button>

Passing CSS class

You can pass classes into child components using property class, to be able to use it in child class you have to place such classes in external block:

Syntax: class:childClassName="parentClass globalClass"

In the example, classes red italic is passed as class font in child component. If class is not passed default styles will be used.

You can pass scoped classes, global classes and use expressions, e.g. class:font="italic {color}"

<!-- App -->
<Child class:font="red italic" />

<!-- Child -->
<div class="font">Child</div>

<style external>
    .font {color: blue;}  /* style by default */
</style>

Default class name for child component is main, and you can define it.

  • Also you can pass partly global classes (e.g. .button :global(.title))
  • Passing pseudo-classes (:hover etc)
  • Forward a class further
<!-- App -->
<Child class="red italic" />

<!-- Child -->
<div class="main">Child</div>

<style external main="main">
    .main {color: blue;}  /* style by default */
</style>

Other

If you have an instance of component, you can read/write properties directly.

<script>
    import Component from './Component.html';
    let comp;

    function increment() {
        comp.value++;
    }
</script>
<Component #comp />

If you need to perform some code after mounting or during destroying a component, you can use declare functions onMount, onDestroy, or use a built function $onDestroy(fn).

<script>

    called_at_start();

    function onMount() {
        // called after mounting

        $onDestroy(() => {...});  // subscribe on destroying
        $onDestroy(() => {...});
    }

    function onDestroy() {
        // called during destroying
    }
</script>
<Component #comp />

Other

Scoped CSS

Malina.js makes all styles are scoped for a component, it appends a prefix class to styles and elements from template based on selector, so only required elements are marked.

Using keyword :global() you make certain style as global.

<style>
    span {
        /* all <span> elements, only from
        current component will be affected */
    }
    :global(body) {
        /* effects on <body> */
    }
    div :global(span) {
        /* effects on all <span> elements
        (including child components)
        inside of <div> from current component */
    }
</style>

Also you can mark whole style-block as global

<style global>
    span { /* ... */ }
</style>

Watch expression, reactivity

Using syntax $: you can observe changes.

Computed value: $: value = a + b, value will be changed when an expression gives another result.

To observe changes in expression and call handler: $: exp, handler(). It can contain a few expressions: $: exp1, exp2, a+b, handler().

Handler also can be link to function or statement: $: exp, (newValue) => console.log(newValue); or $: exp, console.log(exp) or $: exp, handler

<script>
    let name = '';
    $: header = name.toUpperCase();
    $: name, () => console.log(name);
    $: a + b, onChangeSum
</script>

<input type="text" :value={name} />

Compile options

  • warning - to receive warnings
  • inlineTemplate - convert new line to \n
  • hideLabel - hide comment tags (labels) from DOM
  • compact - remove spaces between DOM elements
  • autoSubscribe - autosubscribe imported stores
  • cssGenId - generate hash for css classes