
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
Contributors
Helpful? You can thank these awesome people! You can also edit this doc if you see any issues or want to improve it.