Marko Fundamentals

Tldr

  • 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
<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

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)}
<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
<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
<h1>Our Team</h1>
<card/>
<card/>
<card/>
h1 -- Our Team
card
card
card

Note

Components in the tags/ directory are automatically discovered. Learn more about tag discovery in our reference docs.

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>
div
  h3 -- ${input.name}
  p -- ${input.role}
  p -- Joined ${input.year}
export interface Input {
  name: string;
  role: string;
  year: number;
}

<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}
  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
<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

Tip

In Marko, attribute values are JavaScript expressions. This means they're not limited to just strings and numbers:

<card name="You!" role=input.role joinDate=new Date().getFullYear() + 1/>
card name="You!" role=input.role joinDate=new Date().getFullYear() + 1
<card name="You!" role=input.role joinDate=new Date().getFullYear() + 1/>
card name="You!" role=input.role joinDate=new Date().getFullYear() + 1

Conditionals

We can use conditional tags (<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
<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
<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

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.