1 | # Custom tags
|
2 |
|
3 | Custom tags allow you to break up your application UI into encapsulated, reusable components.
|
4 |
|
5 | ## Your first custom tag
|
6 |
|
7 | Let's say we have a page with the following content:
|
8 |
|
9 | _page.marko_
|
10 |
|
11 | ```marko
|
12 | <!doctype html>
|
13 | <html>
|
14 | <body>
|
15 | <h1>Hello World!</h1>
|
16 | </body>
|
17 | </html>
|
18 | ```
|
19 |
|
20 | 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:
|
21 |
|
22 | _components/hello.marko_
|
23 |
|
24 | ```marko
|
25 | <h1>Hello World!</h1>
|
26 | ```
|
27 |
|
28 | Marko [automatically discovers](#how-tags-are-discovered) `.marko` files under a `components/` directory, so we can now use the `<hello>` tag in our page:
|
29 |
|
30 | _page.marko_
|
31 |
|
32 | ```marko
|
33 | <!doctype html>
|
34 | <html>
|
35 | <body>
|
36 | <hello/>
|
37 | </body>
|
38 | </html>
|
39 | ```
|
40 |
|
41 | 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.
|
42 |
|
43 | _page.marko_
|
44 |
|
45 | ```marko
|
46 | <!doctype html>
|
47 | <html>
|
48 | <body>
|
49 | <hello name="World"/>
|
50 | </body>
|
51 | </html>
|
52 | ```
|
53 |
|
54 | The component will receive these attributes as `input`:
|
55 |
|
56 | _components/hello.marko_
|
57 |
|
58 | ```marko
|
59 | <h1>Hello ${input.name}!</h1>
|
60 | ```
|
61 |
|
62 | Nice.
|
63 |
|
64 | ## How tags are discovered
|
65 |
|
66 | 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.
|
67 |
|
68 | Let's take a look at an example directory structure to better understand this:
|
69 |
|
70 | ```dir
|
71 | components/
|
72 | app-header.marko
|
73 | app-footer.marko
|
74 | pages/
|
75 | about/
|
76 | components/
|
77 | team-members.marko
|
78 | page.marko
|
79 | home/
|
80 | components/
|
81 | home-banner.marko
|
82 | page.marko
|
83 | ```
|
84 |
|
85 | The file `pages/home/page.marko` can use the following tags:
|
86 |
|
87 | - `<app-header>`
|
88 | - `<app-footer>`
|
89 | - `<home-banner>`
|
90 |
|
91 | And the file `pages/about/page.marko` can use the following tags:
|
92 |
|
93 | - `<app-header>`
|
94 | - `<app-footer>`
|
95 | - `<team-members>`
|
96 |
|
97 | 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.
|
98 |
|
99 | ## Tag directories
|
100 |
|
101 | In addition to a Marko template, the children of `components/` can be a directory with an `index.marko` template:
|
102 |
|
103 | ```dir
|
104 | components/
|
105 | app-header/
|
106 | index.marko
|
107 | logo.png
|
108 | style.css
|
109 | app-footer/
|
110 | index.marko
|
111 | ```
|
112 |
|
113 | Or a directory with a template whose name matches its parent directory:
|
114 |
|
115 | ```dir
|
116 | components/
|
117 | app-header/
|
118 | app-header.marko
|
119 | app-header.style.css
|
120 | logo.png
|
121 | app-footer/
|
122 | app-footer.marko
|
123 | ```
|
124 |
|
125 | This allows you to create components that have other files associated with them and keep those files together in the directory structure.
|
126 |
|
127 | > **ProTip:**
|
128 | > You can take advantage of nested `components/` directories to create "subcomponents" that are only available to the component that contains them.
|
129 | >
|
130 | > ```dir
|
131 | > components/
|
132 | > app-header/
|
133 | > components/
|
134 | > navigation.marko
|
135 | > user-info.marko
|
136 | > app-header.marko
|
137 | > app-footer/
|
138 | > app-footer.marko
|
139 | > ```
|
140 |
|
141 | ## Using tags from npm
|
142 |
|
143 | To use [tags from npm](https://www.npmjs.com/search?q=keywords%3Amarko%20components), ensure that the package is installed and listed in your `package.json` dependencies:
|
144 |
|
145 | ```
|
146 | npm install --save @marko/match-media
|
147 | ```
|
148 |
|
149 | Marko discover tags from packages defined in your `package.json`, so you can start using them right away:
|
150 |
|
151 | ```marko
|
152 | <div>
|
153 | <match-media|{ mobile }| mobile="max-width:30em">
|
154 | <!-- nice -->
|
155 | </match-media>
|
156 | </div>
|
157 | ```
|
158 |
|
159 | ## Publishing tags to npm
|
160 |
|
161 | We saw above that tags from npm are automatically discovered. In order to make this work, your package must include a [`marko.json`](./marko-json.md) at the root.
|
162 |
|
163 | _marko.json_
|
164 |
|
165 | ```json
|
166 | {
|
167 | "tags-dir": "./dist/components"
|
168 | }
|
169 | ```
|
170 |
|
171 | This example file tells Marko to expose all components directly under the `dist/components/` directory to the application using your package.
|
172 |
|
173 | We recommend adding the `marko` and `components` keywords to your `package.json` so others can find your components. Then `npm publish`!
|
174 |
|
175 | # Macros
|
176 |
|
177 | The [`<macro>`](./core-tags.md#macro) tag allows you to create custom tags in the same file that they are used in.
|
178 |
|
179 | ```marko
|
180 | <macro|{ name }| name="welcome-message">
|
181 | <h1>Hello ${name}!</h1>
|
182 | </macro>
|
183 |
|
184 | <welcome-message name="Patrick"/>
|
185 | <welcome-message name="Austin"/>
|
186 | ```
|