Marko

Custom tags

Custom tags allow you to break up your application UI into encapsulated, reusable components.

Your first custom tag

Let's say we have a page with the following content:

page.marko
<!doctype html>
<html>
<body>
    <h1>Hello World!</h1>
</body>
</html>
<!doctype html>
html
  body
    h1 -- Hello World!

However, this page is getting pretty complex and unmaintainable. Let's split out the content into a separate component. To do this, we'll create a components/ folder and inside it a hello.marko file:

components/hello.marko
<h1>Hello World!</h1>
h1 -- Hello World!

Marko automatically discovers .marko files under a components/ directory, so we can now use the <hello> tag in our page:

page.marko
<!doctype html>
<html>
<body>
    <hello/>
</body>
</html>
<!doctype html>
html
  body
    hello

Now this <hello> tag can be used multiple times, and even on multiple pages. But what if we don't only want to say hello to the world? Let's pass some attributes.

page.marko
<!doctype html>
<html>
<body>
    <hello name="World"/>
</body>
</html>
<!doctype html>
html
  body
    hello name="World"

The component will receive these attributes as input:

components/hello.marko
<h1>Hello ${input.name}!</h1>
h1 -- Hello ${input.name}!

Nice.

How tags are discovered

Marko discovers components relative to the .marko file where a custom tag is used. From this file, Marko walks up directories until it finds a components/ folder which contains a component matching the name of the custom tag. If it reaches the project root without finding anything, it will then check installed packages for the component.

Let's take a look at an example directory structure to better understand this:

components/
    app-header.marko
    app-footer.marko
pages/
    about/
        components/
            team-members.marko
        page.marko
    home/
        components/
            home-banner.marko
        page.marko

The file pages/home/page.marko can use the following tags:

  • <app-header>
  • <app-footer>
  • <home-banner>

And the file pages/about/page.marko can use the following tags:

  • <app-header>
  • <app-footer>
  • <team-members>

The home page can't see <team-members> and the about page can't see <home-banner>. By using nested component/ directories, we've scoped our page-specific components to their respective pages.

Tag directories

In addition to a Marko template, the children of components/ can be a directory with an index.marko template:

components/
    app-header/
        index.marko
        logo.png
        style.css
    app-footer/
        index.marko

Or a directory with a template whose name matches its parent directory:

components/
    app-header/
        app-header.marko
        app-header.style.css
        logo.png
    app-footer/
        app-footer.marko

This allows you to create components that have other files associated with them and keep those files together in the directory structure.

ProTip: You can take advantage of nested components/ directories to create "subcomponents" that are only available to the component that contains them.

components/
    app-header/
        components/
            navigation.marko
            user-info.marko
        app-header.marko
    app-footer/
        app-footer.marko

Using tags from npm

To use tags from npm, ensure that the package is installed and listed in your package.json dependencies:

npm install --save @marko-tags/match-media

Marko discover tags from packages defined in your package.json, so you can start using them right away:

<div>
    <match-media|{ mobile }| mobile="max-width:30em">
        <!-- nice -->
    </match-media>
</div>
div
  match-media|{ mobile }| mobile="max-width:30em"
    <!-- nice -->

Publishing tags to npm

We saw above that tags from npm are automatically discovered. In order to make this work, your package must include a marko.json at the root.

marko.json
{
  "tags-dir": "./dist/components"
}

This example file tells Marko to expose all components directly under the dist/components/ directory to the application using your package.

We recommend adding the marko and components keywords to your package.json so others can find your components. Then npm publish!

Macros

The <macro> tag allows you to create custom tags in the same file that they are used in.

<macro|{ name }| name="welcome-message">
    <h1>Hello ${name}!</h1>
</macro>

<welcome-message name="Patrick"/>
<welcome-message name="Austin"/>
macro|{ name }| name="welcome-message"
  h1 -- Hello ${name}!

welcome-message name="Patrick"
welcome-message name="Austin"

From Variables

If no other tag would be discovered Marko will check for an in scope variable that matches the tag name.

import SomeTag from "./somewhere.marko"

$ const { renderBody } = input;
$ const MyTag = input.href ? "a" : "button";

<SomeTag/>
<MyTag/>
<renderBody/>
import SomeTag from "./somewhere.marko";
$ const { renderBody } = input;
$ const MyTag = input.href ? "a" : "button";

SomeTag
MyTag
renderBody
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