Tags API docs (not good, here is the [reference](https://hackmd.io/rYm4HNgXQMasqoB0OBwMSQ))
# Marko Language
Marko is a superset over a subset of html.
The goal of Marko is to make HTML more strict (think a linter) while also extending HTML with the ability to represent declarative UI's with control flow and reactive data bindings. It does this by meshing JavaScript syntax features within html's semantics and introducing a few new syntaxes of it's own. Most HTML is valid Marko but there are some important deviations.
## Attributes
The attributes of a tag in Marko come through to the child as an object (the object is available as a render scoped variable called `input`, more on that later).
Attribute values are JavaScript expressions meaning you can do cool things like:
```marko
<my-tag str="Hello"></my-tag>
<my-tag str=`Hello ${name}`></my-tag>
<my-tag num=1 + 1></my-tag>
<my-tag date=new Date()></my-tag>
<my-tag fn=function myFn(param1) { console.log("hi") }></my-tag>
```
Almost all valid JavaScript expressions can be written as the attribute value.
Even with `<my-tag str="Hello">` the `"Hello"` string is a JavaScript string literal and not an html attribute string.
Attributes can be thought of as JavaScript objects in Marko which are passed to a tag.
### Boolean Attributes
Like HTML Marko supports boolean attributes and makes the following equivalent:
```marko
<input type="checkbox" checked>
<input type="checkbox" checked="">
<input type="checkbox" checked=true>
```
### Ignored attributes
If an attribute is `null`, `undefined` or `false` it is skipped when writing out the html.
### Attribute shorthands
Like JavaScript objects, Marko adopts some shorthands for common patterns like:
```marko
// Object rest/spread
// Note the value after the `...` (like in JavaScript) can be any valid JavaScript expression.
// Same as a javascript object like {...spread ...{ stuff }}
<my-tag ...spread ...{ stuff }></my-tag>
// Method shorthand
<my-tag onClick(ev) { console.log(ev.target) }></my-tag>
```
Another important shorthand that we'll get to later is called the "value attribute" which provides a concise way to pass an attribute to a tag without explicitly naming it.
```marko
<my-tag=1></my-tag>
// same as
<my-tag value=1></my-tag>
```
Sometimes it's nice to be able to pass a single unnamed javascript function to a tag, so the method shorthand can be combined the the idea of the value attribute to give us the "value method shorthand"
```marko
<my-tag() {
console.log("Hello JavaScript!");
}/>
// same as
<my-tag value=function () {
console.log("Hello JavaScript!");
}/>
// Received by the child as { value() { ... } }
```
### Attribute termination
Attributes can also be terminated (like it JavaScript objects) with a comma. Eg `<my-tag a=1, b=2>` will parse just fine.
There are a few differences though with Marko's attributes from a JavaScript object such as:
* Attribute names can contain `-`, eg `<my-tag my-value=1>`.
* Values cannot contain an unenclosed `>` since it is ambiguous. You work around that by using parenthesis: `<my-tag value=(1 > 2)>`
## Statements
Marko supports a few special module scoped top level statements.
Firstly JavaScript `import` and `export` statements are allowed at the top level, allowing for code like
```marko
import sum from "sum"
<div data-sum=sum(1, 2)></div>
```
There is also a shorthand for importing Marko components by using angle brackets in the `from` of the import, which will use Marko's custom tag discovery logic.
```marko
import MyTag from "<my-tag>"
```
You can also run arbitrary module scoped JavaScript expressions with the `static` keyword like so:
```marko
static const value = 1
<div data-value=value></div>
```
After the `static` keyword you can have any valid javascript statement, including functions, declarations, conditions, etc, and they will execute in the module scope of the compiled template.
## Comments
Marko supports three types of comments.
```marko
<div>
<!-- html comments -->
// JavaScript line comments
/** JavaScript block comments */
</div>
```
## Close Tags
The closing tag in Marko is always optional if you don't wish to provide body content, meaning `<div/>` is valid.
Marko still provides support for `void` tags like `<input>`, `<br>` which can optionally have the closing `/` like `<br/>`.
If you do have body content, you can still omit repeating the tag name itself when closing the tag like so:
```marko
<div>Hello World</>
```
## Tag Name
The html tag names in Marko are not limited to the standard html tags, but custom ones as well.
### Custom tag discovery
Custom tags are discovered on disk (not a runtime mechanism) using a lookup that resembles `node_module` resolution.
Specifically when a Marko template contains a non html tag, eg `<my-tag>` in previous examples, Marko will walk up directories to the CWD looking inside folders named `components` until it finds `components/my-tag.marko` or `components/my-tag/index.marko`.
If it fails to find a tag using that mechanism it will also check against tags exposed through the `node_modules` installed in the `package.json`. Finally if it can't find a tag it will generally error.
### In scope identifier tag
However if a variable is in scope with the same name as the tag it will use that, eg
```marko
import MyTag from "../components/my-tag.marko"
<MyTag></MyTag>
```
Although in the above example, since the normal discovery mechanism can be used it's simpler to just write
```marko
<my-tag></my-tag>
```
### Dynamic tag name
Besides in identifiers being able to be used as tag names, you can also interpolate in arbitrary expressions as the tag to render by using `${}` within the tag name, like so:
```marko
import MyTagA from "<my-tag-a>"
import MyTagB from "<my-tag-b>"
<${Math.random() > 0.5 ? MyTagA : MyTagB}></>
```
If a `falsey` value is provided as the expression of the tag name it will render the "Body Content" as is.
This is useful for conditionally parenting some text, eg
```marko
<${input.href ? "a" : null} ...input>Hello Maybe Link</>
```
## Body Content
In Marko you can pass body content to a child the same way you would in html.
```marko
<my-tag>Content</my-tag>
```
This will be made available within the `input` object (which contains all of the attributes) under a special property called `renderBody`.
You can then use "Dynamic tag name" syntax to render the body content, just like you would a regular template.
So with the above, a child template could transclude the provided html content in the `renderBody` like so:
```marko
<div>
<${input.renderBody}/>
</div>
```
The `renderBody` can be used any number of times within the child template, or passed anywhere. Ultimately it is a black box that tells a "Dynamic tag name" what to render.
The "Dynamic tag name" will also automatically look for a `renderBody` property on any provided object, which means the above could be simplified to
```marko
<div>
<${input}/>
</div>
```
### Body Content Placeholders
Within the body content you can use template literal style expression interpolation like so:
```marko
<div>
Hello ${input.name} // Remember `input` is contains the attributes passed in from the parent.
</div>
```
Any valid JavaScript expression is allowed within the `${}`.
The text within an interpolation is automatically escaped to avoid XSS.
You can however render unescaped html using `$!{}` instead.
### Tag Body Parameters
When rendering body content you can pass attributes back to the parent when you use the `renderBody` like so:
```marko
<${input.renderBody} number=1337 />
```
The attributes object in this case comes through to the parent as the first "Tag Parameter".
"Tag Parameters" is a syntax that allows you to receive data from a child component when it renders the render body. It uses a `|pipes|` syntax after the tag name that allows for JavaScript function parameter syntax within the enclosing pipes.
In this case the parent could read those attributes from the child rendering the body like so
```marko
<my-tag|attrs|>
Child gave us ${attrs.number}
</my-tag>
```
Since within the `|pipes|` we use the JavaScript function parameters syntax you use features like destructuring:
```marko
<my-tag|{ number }|>
Child gave us ${number}
</my-tag>
```
Finally you can also pass multiple "Tag parameters" to the parent's provided body content by using the "Tag Arguments" syntax, which is simply JavaScript style `(...args)` after the tag name. In this case combined with rendering the body content from input we could have something like
```marko
<${input.renderBody}(1, 2, 3)/>
```
The parent could receive these parameters like so
```marko
<my-tag|a, b, c|>
Sum ${a + b + c}
</my-tag>
// spreads work also!
<my-tag|...all|>
Sum ${all.reduce((a, b) => a + b, 0)}
</my-tag>
```
### Named Body Content (AKA Attribute Tags)
In Marko you can also provide "named" body content to a child tag using the "Attribute Tag" syntax.
An "Attribute Tag" is any tag within another that is prefixed with an `@`.
Attribute tags within the body will be provided to the parent component as an attribute (hence the name).
Te parent is provided a property with the name of the tag (excluding the leading `@`). Te value of the property is an object with all of the attributes rendered on the attribute tag (including it's `renderBody`).
```marko
<my-layout title="Welcome">
<@header class="foo">
Hello Header
</@header>
<@footer class="bar">
Hello Footer
</@header>
</my-layout>
```
In this case the `my-layout` component would receive an `input` object like
```js
{
title: "Welcome",
header: {
class: "foo",
renderBody(){...},
[Symbol.iterator]() {...}
},
body: {
class: "foo",
renderBody(){...},
[Symbol.iterator]() {...}
}
}
```
#### Repeated Attribute Tags
Note the `Symbol.iterator` above. This is there because "Attribute tags" are "Iterable".
In this case the `@header` and `@footer` are rendered once, but you can actually provide the same attribute tag name multiple times.
When doing so, the child component can consume them all through the iterator.
```marko
<my-menu>
<@item value="foo">
Foo Item
</@item>
<@item value="bar">
Bar Item
</@item>
</my-layout>
```
In the above the parent provides two "@foo" attribute tags.
The child would receive `input.item` in this case which is the first rendered attribute tag. However the child can read all of the attribute tags by consuming the attribute tags iterator like so
```marko
<div>
${[...input.item].map(item => item.value)} // would print foo,bar
</div>
```
Repeated attribute tags like this are often iterated over to display there contents.
Since the built in `<for of>` tag supports iterables (like JavaScripts `for(x of y)` loop) you can also read all of the attribute tags using that.
```marko
// We consume all `item`'s since it's an iterable.
<for|item| of=input.item>
Value: ${item.value} // We can read properties from each item.
<${item.renderBody}/> // And render it's content.
</for>
```
#### Nested Attribute tags
When attribute tags are nested which will simply add the nested attribute as an attribute on it's direct parent attribute tag.
```marko
<my-tag>
<@a value=1>
<@b value=2/>
</>
```
Would provide the following as input
```js
{
a: {
value: 2,
b: { value: 2 }
}
}
```
#### Attribute Tag Control flow
Attribute tags generally are provided directly to their immediate parent (even when nested). One exception to this is with the `<for>` and `<if>` control flow tags.
```marko
<my-message>
<if=welcome>
<@title>Hello</>
</if>
<else>
<@title>Good Bye</>
</>
</my-message>
```
After the above `<if>` evaluates it will apply either the attribute tags within the `<if>` or `<else>` accordingly to the `<my-message>` tag.
```marko
<my-select>
<for|opt| of=["a", "b", "c"]>
<@option>Option: ${opt}</>
</for>
</my-tag>
```
In the above with a `<for>` control flow tag, it will conceptually render `n` number of `<@option>` attribute tags and provide them to `<my-select>`. Note if the `<for>` loop does not render a single item, the child will receive the `input.option` as undefined (as if there were no attribute tags with that name at all).
## Tag Variables
Custom tags can also have a return value which is received in the "Tag Variable" syntax.
A tag variable uses a `/` followed by a valid JavaScript identifier, or destructure pattern, after the tag name.
Native tags have an implicitly returned tag variable that gives a reference to the element, eg
```marko
<div/myDiv/>
```
In this case `myDiv` will be a variable which can be called to get the `myDiv` element in the browser.
Using the `<return>` tag, any custom tag can give back any value into it's parents scope as a tag variable.
# Core Tags
In the syntax guide above I tried to avoid using "Core Tags" because a principle of Marko is that as much of the language as possible is consistent and composable, meaning it can be used by the "core" api and in userland.
Now I'll list tags that ship with Marko to provide important functionality.
## if/else-if/else
The `<if>`, `<else-if>` and `<else>` (which supports and `if` attribute) tags allow conditionally rendering body content
`if` and `else-if` can receive a `value` attribute (shorthand used below) to display body content if a condition is meant.
Like JavaScript each expression in the if/else-if change is evaluated in order.
```marko
<if=EXPRESSION>
Body A
</>
<else-if=OTHER_EXPRESSION>
Body B
</>
<else>
Body C
</>
```
## for
The `<for>` tag is for iterating while rendering body content. It uses the "Tag Parameters" syntax to make the data for an interation available within the body content.
There are three types of `<for>` loop styles in Marko
```marko
<ol>
// Iterates over any javascript iterable and provides parameters similar to Array.prototype.map.
// Note if the `of` value is `falsey` nothing will be rendered and no error thrown.
<for|color, index, colorList| of=["red", "green", "blue"]>
<li value=index>${color}</li>
</for>
</ol>
<dl>
<for|name, enabled| in={
"Dark Mode": false,
"Fullscreen": true
}>
// Iterates over any javascript object using a `for in` loop.
<dt>${name}:</dt>
<dd>${enabled ? "on" : "off"}</dd>
</for>
</dl>
<ol type="I">
<for|i| from=0 to=10 step=2>
// Iterates over a range of numbers
<li value=i>${i}</li>
</for>
</ol>
```
## let
The `<let>` tag introduces state into a template.
```marko
<let/x=1/>
```
A let uses both the `"Tag Variable"` syntax and the "value attribute" syntax.
The `let` tag allows you to initialize a state, and any time the value is written two, any thing that references the state will be updated. Eg
```marko
<let/count=1/>
<button onClick() { count++ }>
Current count: ${count}
</button>
```
in the above every time the button is clicked, `count` get's updated. But because `count` is not just an ordinary JavaScript variable but a Marko "Tag Variable" it will cause any down stream expression of count (in this case the text in the button) to be updated.
## const
The `<const>` tag reflects as it's "Tag Variable" whatever was passed in as it's value.
Extending the `<let>` example we could derive data from the `count` state like so:
```marko
<let/count=1/>
<const/doubleCount=count * 2/>
<button onClick() { count++ }>
Current count: ${count}
And the double is ${doubleCount}
</button>
```
We can store the `count * 2` expression and get a reference to it thanks to the `<const>` tag.
## return
The `<return>` tag allows any custom tag to provide a "Tag Variable".
In fact the implementation of the `<const>` tag above is conceptually the same as
```marko
<return=input.value/>
```
## define
The `<define>` tag is a lot like an "Attribute Tag" except that it gives you the object back as a variable.
```marko
<define/MyTag|input| some-attr=1>
Hello World
</>
<MyTag/>
<div>${MyTag["some-attr"]}</>
```
## effect
The `<effect>` tag lets us synchronize the declarative Marko template with the messy imperative world.
You provide the `<effect>` tag a function as the "value attribute" and it will run that function first when the template has finished rendering and is mounted in the browser, and then again after any "Tag Variable" it references are updated.
```marko
<let/count=1/>
<button/myButton onClick() { count++ }>
Current count: ${count}
</button>
<effect() {
// Runs in the browser always after everything has rendered.
// Also runs when either `myButton` or `count` updates since they are referenced.
console.log("clicked", myButton(), count, "times");
}/>
```
## lifecycle
The `<lifecycle>` tag is much like the `<effect>` tag and gives you synchronize the Marko template with imperative API's in the browser.
The main difference is that the `<lifecycle>` tag gives you finer control, and gives you a place to store mutable data.
```marko
<lifecycle
onMount() {
// Called once this lifecycle tag is attached to the dom, and never again.
}
onUpdate() {
// Called every time the dependencies of the `onUpdate` function are invalidated.
}
onDestroy() {
// Called once this lifecycle is removed from the dom.
}
/>
```
Besides the three methods above, you can also add other methods and properties to the `lifecycle` attributes which will be available as the `this` within the methods.
The `this` within these methods is consistent across the life time of the lifecycle tag and can be mutated.
Using these tools it is easy to integrate with many tools exposing imperative apis.
```marko
client import { Map } from "map-api";
<let/lat = 0/>
<let/lon = 0/>
<div/container/>
<lifecycle
onMount() {
this.map = new Map({ lat, lon, zoom: 8 });
this.map.show(container());
}
onDestroy() {
this.map.destroy();
}
onUpdate() {
this.map.setCoords(lat, lon);
}
/>
```
## context
The `<context>` tag allows for providing data to a subtree of rendered components.
To provide data you can pass a `value` attribute to the `<context>` tag, and some body content which will later read the data.
```marko
<context=42>
<MyTag/>
</context>
```
Now somewhere deep within `MyTag` we could read the context using the same tag. When passed a `from` attribute that points to a Marko template the `<context>` tag will find the closest context for that template in the tree and make it's value the "Tag Variable" for the context tag.
```marko
import Provider from "./provider.marko" // the previous template that provided the context.
<context/answer from=Provider/>
```
The context tag also supports a special shorthand to skip the `import` of the template, the `from` attribute of the `<context>` tag can be (static) string that resolves to a template instead.
With that the above could be written as:
```marko
<context/answer from="./provider.marko"/>
// Or, using the component import shorthand
<context/answer from="<provider>"/>
```