Marko Fundamentals

TL;DR

Marko builds on top of HTML, enabling components and JavaScript-based interpolation

Marko is designed to feel familiar if you know HTML, while making it easy to build dynamic, interactive websites. Let's walk through the core concepts.

Templates are HTML

Nearly any valid HTML is also valid Marko code. We can start with regular HTML and gradually add features as needed.

<h1>My Blog</h1>
<nav>
  <a href="/about">
    About
  </a>
  <a href="/contact">
    Contact
  </a>
</nav>
h1 -- My Blog
nav
  a href="/about" -- About
  a href="/contact" -- Contact

Attributes are JS

Almost all valid JavaScript expressions can be written as attribute values.

<a href=`/user/${user.id}`>
  My Profile
</a>
<a href=getRandomPage()>
  Discover Something New
</a>
a href=`/user/${user.id}` -- My Profile
a href=getRandomPage() -- Discover Something New
Note

The Reference Docs explain more about Attributes including how they support ...spreads and methods().

Dynamic Content

Tag content in Marko is similar to template literals in JavaScript, so dynamic text can be added with interpolated ${expressions}

<p>Today is ${new Date().toDateString()}</p>
<p>Random number: ${Math.floor(Math.random() * 100)}</p>
p -- Today is ${new Date().toDateString()}
p -- Random number: ${Math.floor(Math.random() * 100)}

Components

To reuse code, we can move it into a separate file. Each .marko file is a component that can be used like an HTML tag.

tags/card.marko
<div>
  <h3>Alice</h3>
  <p>Designer</p>
  <p>Joined 2023</p>
</div>
div
  h3 -- Alice
  p -- Designer
  p -- Joined 2023

This <card> component can now be used anywhere in the page:

<h1>Our Team</h1>
<card/>
<card/>
<card/>
h1 -- Our Team
card
card
card
Note

Components in the tags/ directory are automatically discovered. No need to import them.

Tip

We can also write multiple "components" in a single file using the <define> tag.

Passing Data to Components

Attributes on custom components are available through a special object called input.

card.marko
<div>
  <h3>${input.name}</h3>
  <p>${input.role}</p>
  <p>Joined ${input.year}</p>
</div>
export interface Input {
  name: string;
  role: string;
  year: number;
}

<div>
  <h3>${input.name}</h3>
  <p>${input.role}</p>
  <p>Joined ${input.year}</p>
</div>
div
  h3 -- ${input.name}
  p -- ${input.role}
  p -- Joined ${input.year}
export interface Input {
  name: string;
  role: string;
  year: number;
}

div
  h3 -- ${input.name}
  p -- ${input.role}
  p -- Joined ${input.year}

Now we can pass different data to each instance of card:

<h1>Our Team</h1>
<card name="Alice" role="Designer" year=2023/>
<card name="Bob" role="Developer" year=2024/>
<card name="Charlie" role="Product Manager" year=2022/>
h1 -- Our Team
card name="Alice" role="Designer" year=2023
card name="Bob" role="Developer" year=2024
card name="Charlie" role="Product Manager" year=2022
Note

Also check out attribute tags which we can use to pass named content to a component

Core Tags

Marko provides many helpful Core Tags. For example, we can use <if> and <else> to show or hide content based on conditions.

tags/product.marko
<div>
  <h3>${input.name}</h3>
  <p>$${input.price}</p>
  <if=input.stock>
    <button>Add to Cart</button>
  </if>
  <else>
    <button disabled>
      Out of Stock
    </button>
  </else>
</div>
div
  h3 -- ${input.name}
  p -- $${input.price}
  if=input.stock
    button -- Add to Cart
  else
    button disabled -- Out of Stock

Now we can show different states based on the product data:

<product name="T-Shirt" price=25 stock=10/>
<product name="Hoodie" price=45 stock=0/>
<product name="Hat" price=15 stock=5/>
product name="T-Shirt" price=25 stock=10
product name="Hoodie" price=45 stock=0
product name="Hat" price=15 stock=5

And we can use the <for> tag to display repeated content

<for|product| of=productsList>
  <product name=product.name price=product.price stock=product.stock/>
</for>
for|product| of=productsList
  product name=product.name price=product.price stock=product.stock

Next Steps


Contributors

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