Marko

Conditionals and Lists

While HTML itself does not support conditionally displaying elements or repeating elements, it is a critical part of building any web application. In Marko, this functionality is provided by the <if> and <for> tags.

Conditionals

The <if> tag receives an argument which is used to determine if its body content should be present.

<if(user.loggedOut)>
    <a href="/login">Log in</a>
</if>
if(user.loggedOut)
  a href="/login" -- Log in

As you might expect, there are also <else> and <else-if> tags as well:

<if(user.loggedOut)>
    <a href="/login">Log in</a>
</if>
<else-if(!user.trappedForever)>
    <a href="/logout">Log out</a>
</else-if>
<else>
    Hey ${user.name}!
</else>
if(user.loggedOut)
  a href="/login" -- Log in
else-if(!user.trappedForever)
  a href="/logout" -- Log out
else -- Hey ${user.name}!

Lists

If you have a list of data and need to represent it in the UI, the <for> tag is probably what you're looking for. The <for> tag passes each item and its index to its body as parameters.

<ul>
    <for|color, index| of=colors>
        <li>${index}: ${color}</li>
    </for>
</ul>
ul
  for|color, index| of=colors
    li -- ${index}: ${color}

The <for> tag actually support 3 different flavors:

Always set a key

Marko automatically keeps your UI in sync with the state behind it, but one place where it needs a little extra help is repeated content. Specifying keys gives Marko a way to identify items in a list and keep track of which items have been changed, added, or removed.

A key should be a string or number that uniquely identifies an item in the list and differentiates it from its siblings. The same key value should never be used twice! Often, you will use something like an id property.

<for|user| of=users>
    <user-card key=user.id data=user/>
</for>
for|user| of=users
  user-card key=user.id data=user

ProTip: If you have multiple tags underneath <for>, you can key only the first tag and that is enough to properly identify its siblings as well

<dl>
    <for|entry| of=entries>
        <!-- only the first tag needs a key -->
        <dt key=entry.id>${entry.word}</dt>
        <!-- This key can be omitted -->
        <dd>${entry.definition}</dd>
    </for>
</dl>
dl
  for|entry| of=entries
    <!-- only the first tag needs a key -->
    dt key=entry.id -- ${entry.word}
    <!-- This key can be omitted -->
    dd -- ${entry.definition}

Note: If a key is not set, Marko will use the index of an item as its key. However this only works perfectly if items are only ever added or removed at the end of a list. Here's an example where things break down: if we have a list of ["A", "B", "C"] and reverse the order, index keys would cause "A" to be transformed into "C" (and "C" into "A"), rather than just swapping them. Additionally if these components contained state, the new "C" would contain the state from the old "A" (and vice-versa). Be aware, stateful components include tags like the native <input> element. For this reason it is always recommended to set a key on tags in a <for>.

EDIT on GitHub

Contributors

Helpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.

Chat in Marko's Discord Server