# Marko Tags API Reference ## Syntax Marko is roughly a superset of the HTML, reimagined as a language for building dynamic and reactive user interfaces. Most `.html` files can also compile as `.marko` files, but Marko also extends the language to provide tools which allow building modern applications in a declarative way. > **ProTip** > Marko also supports a [beautiful concise syntax](#Shorthands-amp-Concise-Mode). If you'd prefer to see the documentation using this syntax, just click the "Switch Syntax" button in the corner of any Marko code sample. Map of Marko's tag syntax: <pre> <<a href="#Tags">tagName</a>|<a href="#Tag-Parameters">tag,parameters</a>|/<a href="#Tag-Variables">tagVariable</a> ...<a href="#Attributes">attributes</a>> <a href="#Render-Bodies">renderBody</a> <@<a href="#Attribute-Tags">attrTag</a>> </tagName> </pre> > Using links like this might only work in HackMD's Markdown Parser [name=Luke] ## Tags All native HTML tags are also supported in Marko. In addition, Marko comes with a set of [core tags](#Core-Tags) which may be used as building blocks for [custom tags](#Custom-Tags). All of these types of tags use the same syntax, which is identical to HTML: ```marko <tag-with-renderBody> renderBody </tag-with-renderBody> <self-closing-tag/> ``` ### Attributes Attributes are _mostly_ the same as HTML, but their contents are parsed as _JavaScript expressions_ instead of strings. With few exceptions, this is an extension of HTML. All of the following are valid attributes in Marko: ```marko <my-tag attrString="hello" attrNumber=3 attrExpression=5+7 attrVariable=myValue attrList=["a", "b", "c"] attrObject={a: "a", b: "b"} attrFunction=() => {} /> ``` > **ProTip** > See the [shorthands & concise mode](#Shorthands-amp-Concise-Mode) section for a few built-in features that can make attributes easier to read. Marko's parser is able to figure out when each expression ends and another attribute begins, so no parentheses are needed except in rare ambiguous cases such as the `>` operator: ```marko <my-tag isGreater=(4 > 3)></my-tag> ``` Similarly to HTML, Marko parses attributes _without_ any arguments as `true`: ```marko <input type="checkbox" checked> // identical to <input type="checkbox" checked=true> ``` JavaScript-style object spreads are also allowed, where each key and its value are mapped to an attribute. ```marko <input ...{type: "checkbox", checked: true}> ``` ### Body Content Just like in JavaScript's `` `template strings` ``, tag bodies may use `${placeholders}` to interpolate values: ```marko <div> Hello ${"world".toUpperCase()} </div> ``` > **Warning** > Values inside placeholders are automatically escaped to prevent the injection of malicious code. For cases where the developer wants to insert HTML directly and is _certain_ that code injection is not possible, an `!` may be added to pass unescaped HTML: > ```marko > <div> > Hello $!{"<b>World</b>"} > </div> > ``` > **Note** > If necessary, the placeholder `$` may be escaped with a `\`: > ```marko > <div> > Placeholder example: <code>\${someValue}</code> > </div> > ``` ### Attribute Tags The final way to pass attributes in Marko is with `<@attribute-tags>`. It is technically possible to acheive everything that Marko has to offer without using these, but they provide an alternative method for passing complicated render bodies to components: ```marko <my-select> <@option>A</@option> <@option>B</@option> </my-select> // identical to <my-select option=[ { renderBody: "A" }, { renderBody: "B" } ] /> ``` <!-- TODO: Explain the `MaybeArray` situation, and go into a little more depth with the finer details of attr tags --> ### Tag Variables In Marko, tags may also provide a **return value** to the template where they are referenced. The data type of these values is in many ways similar to that of JavaScript variables, but they also trigger updates to their dependencies every time _their tag_ provides a new value. Tag variables will be explored further for [native tags](#Native-Tag-References), core tags and custom tags, but the syntax is always as follows: ```marko <my-tag/tagVariable /> ``` ### Tag Parameters While passing a `renderBody`, tags may also specify parameters which can be passed back by the child template. These values are not the same as tag variables, because they are only accessible within the render body. _parent.marko_ ```marko <child|a, b|> ${a}: ${b} </child> ``` _child.marko_ ```marko <${renderBody}=[a, b]/> ``` ## Native Tags Native tags in Marko are nearly identical to native tags in HTML, with a few additional features. ### Event handlers Event handlers such as `onclick` are supported in native tags, but since they only are only able to receive strings it is not possible to attach them to any of Marko's features. Instead, Marko provides special event handlers on all native tags that are compiled as JavaScript. These are accessed via special camelCase `onEvent` or kebab-case `on-event` attributes. Each of the following examples run the function body every time the `"hover"` event is triggered on the button: ```marko <button onHover=() => { /* runs on hover */ } /> <button on-hover=function() { /* runs on hover */ } /> <button onHover() { /* runs on hover */ } /> ``` > **Note** > Due to the nature of camelCase, the `onEvent` option cannot be used to handle events that begin with capital letters. To handle an `Uppercase` event, use `on-Uppercase`. ### Special Case Attributes In addition to strings, the `class` and `style` attribute accept arrays or objects that will be converted to strings automatically by Marko. The output of each of these cases is identical: ```marko // string <div class="a c" style="display:block;margin-right:16px" /> // object <div class={ a: true, b: false, c: true} style={ display: "block", color: false, marginRight: 16 } /> // array <div class=["a", null, { c: true }] style=["display:block", null, { marginRight: 16 }] /> ``` ### Native Tag References Every native tag provides a [tag variable](#Tag-variables) which acts as a getter function for a reference to its DOM object. ```marko <div/myDiv>Hello World</div> <div> The previous element says ${myDiv().innerHTML} </div> ``` This is only the case for built-in HTML elements. Conceptually, native tags can be thought of as having something like `<return=() => ref />` under the hood. ## Custom Tags / Components Custom tags are single-file blocks of code that are used to separate an application into encapsulated, reusable components. Tags are discovered automatically based on file name, and treated as if they were built into Marko as HTML or core tags. _components/hello.marko_ ```marko <h1>Hello World</h1> ``` _page.marko_ ```marko <html> <body> <hello/> </body> </html> ``` _result.html_ ```html <html> <body> <h1>Hello World</h1> </body> </html> ``` ### `input` Every component file has access to a global variable called `input`, which acts as an object that contains its attributes. _components/hello.marko_ ```marko <h1>Hello ${input.name}</h1> ``` _page.marko_ ```marko <html> <body> <hello name="Marko" /> </body> </html> ``` _result.html_ ```html <html> <body> <h1>Hello Marko</h1> </body> </html> ``` ### `renderBody` The [body content](#Body-Content) of each component is accessible in a component file as a member of the `input` object called `renderBody`: _fancy-border.marko_ ```marko <div class="fancy-border"> <${input.renderBody}/> </div> ``` ## Core Tags > Not sure if we should do alphabetical order or order of importance. This is roughly just the order I remembered them in[name=Luke] ### `<if>`/`<else-if>`/`<else>` These tags are used to conditionally render information. `if` and `else-if` will render their contents when their `value` attribute is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), while `else-if` and `else` act as fallbacks for their previous conditional sibling. ```marko <if value=arriving> Hey there </if> <else-if=leaving> Bye now </else-if> <else> What’s up? </else> ``` > **ProTip** > See the [default value](#Default-Value) shorthand for a more concise way of writing `if` and `else-if` statements. ### `<for>` Just like JavaScript's `for` loops, the Marko `<for>` tag can iterate over [arrays/array-likes](#for-of), [object properties and values](#for-in), and [ranges of numbers](#for-to). The items being iterated over are received as [tag parameters](#Tag-Parameters) which may be used in the [body content](#Body-Content) of the tag. #### for-of ```marko <for|item| of=["a", "b", "c"]> ${item} </for> ``` #### for-in ```marko <for|key, value| in={a: 1, b: 2, c: 3}> ${key}: ${value} </for> ``` #### for-to ```marko <for|num| to=5>${num}, </for> // 0, 1, 2, 3, 4, 5, <for|num| from=3 to=7>${num}, </for> // 3, 4, 5, 6, 7, <for|num| from=2 to=10 step=2>${num}, </for> // 2, 4, 6, 8, 10, ``` #### for-until ???? > This doesn't exist yet but maybe adding it to the docs will be enough to convince the team it's worth including in Marko 6 [name=Luke] ```marko <for|num| until=5>${num}, </for> // 0, 1, 2, 3, 4, <for|num| from=3 until=7>${num}, </for> // 3, 4, 5, 6, <for|num| from=2 until=10 step=2>${num}, </for> // 2, 4, 6, 8, ``` ### `<let>` ```marko <let/x=4/> ``` ```marko <let/_x="HELLO" /> <let/x=_x valueChange(newValue) { _x = newValue.toUpperCase() } /> ``` ### `<const>` Declares a reactive, derived value which updates whenever any of its dependencies change. ```marko <const/doubleX=x*2 /> ``` Conceptually, under the hood the implementaton of the `<const>` tag looks like this: _const.marko_ ```marko <return=input.value/> ``` ### `<effect>` Declares a function which re-runs when its dependencies change ```marko <effect() { console.log(doubleX); // will log every time `doubleX` updates }/> ``` ### `<lifecycle>` Provides code which is only run on the client, throughout the lifecycle of a component. Consistent data can be stored in `this`. #### onMount Fires when the component is first created #### onUpdate Identical to the `<effect>` tag, but with access to its lifecycle's `this`. #### onDestroy Fires before the component is destroyed ```marko <lifecycle onMount() { // create utility } onUpdate() { // use utility } onDestroy() { // destroy utility } /> ``` ### `<return>` _my-const.marko_ ```marko <return=input.value/> ``` ### `<id>` Generates a unique id string which may be safely referenced across the server-client boundary. ```marko <id/inputId /> <label for=inputId>...</label> <input id=inputId /> ``` ### `<html-comment>` Normal HTML comments are automatically stripped from Marko files, these will not ```marko <html-comment>Visible in the client</html-comment> ``` ### `<define>` Almost the same as the `<const>` tag, but it gives back a whole object instead of just `value`. Can be used as an alternative to file-based tags ```marko <define/fancyButton|{renderBody}|> <button class="fancy"><${renderBody}/></button> </define> <fancyButton>Hello!</fancyButton> ``` Essentially, this is the tag's implementation under the hood: _define.marko_ ```marko <return=input/> ``` ## Shorthands & Concise Mode ### Default Value If the first attribute in a tag doesn't have a name, Marko will automatically call it "value". Core tags take advantage of this, which is why these are equivalent: ```marko <let/x value=1/> <let/x=1/> ``` ### Change bindings ```marko <let/count=0 /> <counter count:=count /> // transforms to <counter count=count countChange(c) { count = c } /> ``` _counter.marko_ ```marko <let/count:=input.count /> <button onClick() { count++ }>${count}</button> // transforms to <let/count=input.count valueChange=input.countChange /> ``` ### `class` and `id` shorthands Marko allows tag names to be written using a limited CSS selector syntax to include classes and ids: ```marko <div#main.container /> // equivalent to <div id="main" class="container" /> ``` ### Concise Mode ## Behavior - Dependency tracking of functions - An expression is reevaluated whenever its dependencies change - Resumability (render once server vs client)