Back to Marko Js

Custom Tag Discovery

docs/reference/custom-tag.md

latest4.0 KB
Original Source

Custom Tag Discovery

Custom Tags in Marko allow for reusing markup across the application.

Priority

When you use a <Tag> in Marko it is resolved in the following order:

Local Variable Custom Tags

If a tag name starts with an uppercase letter, Marko first checks for a local variable with the same name.

This is useful for importing custom tags that can't be discovered automatically.

marko
import MyTag from "./my-tag.marko"

<MyTag/>

or when using the <define> tag

marko
<define/MyTag|input: { name: string }| foo=1>
  <span>Hello ${input.name}</span>
</>

<MyTag name="HTML"/>
<MyTag name="Marko"/>

[!NOTE] If you need to reference a local variable that is not PascalCase, you can do so using a dynamic tag.

marko
import { camelCaseTag } from "somewhere"

<${camelCaseTag} />

Relative Custom Tags

If Marko did not resolve a local variable tag name it checks the file system. From the current file, it looks recursively upward for:

  • tags/TAG_NAME.marko
  • tags/TAG_NAME/index.marko
  • tags/TAG_NAME/TAG_NAME.marko

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

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

The file pages/home/page.marko can resolve:

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

And the file pages/about/page.marko can resolve:

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

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

[!NOTE] In previous versions, relative tags were discovered in components/ directories instead of tags/. These directories are now used as a heuristic for runtime interoperability.

Installed Custom Tags

If no Local Variable or Relative Custom Tag is found, Marko checks installed tag libraries in your node_modules.

Packages that provide Marko Custom Tags must include a marko.json at the root which tells Marko where the exported tags are.

json
/* marko.json */
{
  "exports": "./dist/tags"
}

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

[!TIP] Often a tag library will have "private tags" and "exported tags". A common way to achieve this is to have a tags/ folder within the exported tags/ folder 🤯.

For example, when exporting dist/tags, dist/tags/tags/ could contain private components only available within the library.

<!---->

[!CAUTION] If two packages export the tag name, Marko will choose the one it finds first. To prevent collisions, tag libraries are encouraged to prefix all exported tag names, e.g. ebay-. If you must use tags with conflicting names, you can import by path to disambiguate.

Supporting Files

Marko discovers style and marko-tag.json files adjacent to the .marko file.

text
foo.marko
foo.style.css
foo.marko-tag.json

Here, the <foo> tag has associated styles and metadata.

When the file is named index.marko the prefix is optional.

text
tags/
  bar/
    index.marko
    style.css
  baz/
    index.marko
    marko-tag.json

Here, the <bar> tag has an associated style.css and the <baz> tag has an associated marko-tag.json.

For style files any extension may be used allowing for CSS preprocessors.

text
tags/
  less/
    index.marko
    style.less
  scss/
    index.marko
    style.scss