Node Types Reference
Meno pages are built from a tree of typed nodes. Every node has a type field that determines its behavior, available properties, and how it renders to HTML during static build.
There are 7 node types: node, component, link, embed, list, locale-list, and slot.
1. node (HTML Element)
Renders a standard HTML element. This is the most common node type.
Properties
Property | Type | Required | Description |
|---|---|---|---|
|
| Yes | Node type discriminator |
|
| Yes | HTML tag name ( |
|
| No | Responsive style object with |
| `Record<string, string | number | boolean>` | No | HTML attributes ( |
| `string | (string | Node)[]` | No | Text content or array of child nodes and strings |
|
| No | Custom label displayed in the editor structure tree |
|
| No | CSS rules for pseudo-states like |
| `boolean | object | string` | No | Conditional rendering expression |
|
| No | Generate an element class without any styles (for custom CSS) |
Examples
Basic container with padding:
{
"type": "node",
"tag": "div",
"style": { "base": { "padding": "16px", "display": "flex", "gap": "12px" } },
"children": [
{ "type": "node", "tag": "span", "children": "Hello" },
{ "type": "node", "tag": "span", "children": "World" }
]
}Image element (void element, no children):
{
"type": "node",
"tag": "img",
"attributes": {
"src": "/hero.jpg",
"alt": "Hero image",
"fetchpriority": "high",
"loading": "eager",
"width": "1200",
"height": "600"
}
}Text content does NOT use a text property. Always use children:
{
"type": "node",
"tag": "p",
"children": "This is a paragraph."
}Mixed text and inline elements:
{
"type": "node",
"tag": "p",
"children": [
"Read our ",
{ "type": "node", "tag": "strong", "children": "documentation" },
" to learn more."
]
}2. component (Component Instance)
Renders an instance of a reusable component defined in components/*.json.
Properties
Property | Type | Required | Description |
|---|---|---|---|
|
| Yes | Node type discriminator |
|
| Yes | Name of the component (matches filename without |
|
| No | Prop values passed to the component |
| `(string | Node)[]` | No | Children inserted into the component's |
| `Record<string, string | number | boolean>` | No | HTML attributes on the wrapper element |
|
| No | Wrapper style (prefer using props with style mappings instead) |
|
| No | Custom label in the editor structure tree |
| `boolean | object | string` | No | Conditional rendering expression |
Do not add style directly to component instances unless necessary. Define props in the component interface that map to styles via _mapping objects.
Examples
Simple component with props:
{
"type": "component",
"component": "Button",
"props": { "text": "Click me", "variant": "primary" }
}Component with slot children:
{
"type": "component",
"component": "Card",
"props": { "title": "Featured" },
"children": [
{ "type": "node", "tag": "p", "children": "Card body content goes here." }
]
}3. link
Renders as a <div> in the editor and as an <a> tag in the static build.
Properties
Property | Type | Required | Description |
|---|---|---|---|
|
| Yes | Node type discriminator |
| `string | LinkMapping` | Yes | URL string or link mapping object |
| `string | (string | Node)[]` | No | Link content |
|
| No | Responsive style object |
| `Record<string, string | number | boolean>` | No | HTML attributes (e.g., |
|
| No | Custom label in the editor structure tree |
|
| No | CSS rules for pseudo-states |
| `boolean | object | string` | No | Conditional rendering expression |
Examples
Static link:
{
"type": "link",
"href": "/about",
"children": ["Learn more"]
}Link with target attribute:
{
"type": "link",
"href": "https://github.com",
"attributes": { "target": "_blank", "rel": "noopener noreferrer" },
"children": ["GitHub"]
}Dynamic href in a component (using a link-type prop):
{
"type": "link",
"href": "{{link}}",
"children": ["{{linkText}}"]
}The component interface defines the prop as:
{
"link": { "type": "link", "default": { "href": "/", "target": "_blank" } }
}Link mapping for prop-based href resolution:
{
"type": "link",
"href": { "_mapping": true, "prop": "link" }
}4. embed
Renders raw HTML or SVG content. Useful for icons, third-party widgets, or custom markup.
Properties
Property | Type | Required | Description |
|---|---|---|---|
|
| Yes | Node type discriminator |
|
| Yes | Raw HTML/SVG string |
|
| No | Responsive style object for the wrapper |
| `Record<string, string | number | boolean>` | No | HTML attributes on the wrapper |
|
| No | Custom label in the editor structure tree |
| `boolean | object | string` | No | Conditional rendering expression |
Examples
SVG icon:
{
"type": "embed",
"html": "<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"><path d=\"M5 12h14M12 5l7 7-7 7\"/></svg>",
"style": { "base": { "width": "24px", "height": "24px" } }
}Third-party embed:
{
"type": "embed",
"html": "<iframe src=\"https://www.youtube.com/embed/dQw4w9WgXcQ\" frameborder=\"0\" allowfullscreen></iframe>",
"style": { "base": { "width": "100%", "aspectRatio": "16/9" } }
}5. list
Renders children repeatedly for each item from a data source. Supports two source types: component props (prop) and CMS collections (collection).
Properties
Property | Type | Required | Default | Description |
|---|---|---|---|---|
|
| Yes | Node type discriminator | |
| `"prop" | "collection"` | No |
| Where items come from |
|
| Yes | Prop name or collection name | |
| `string | false` | No |
| Container element tag, or |
|
| No |
| Variable name for each item in templates |
|
| No | Maximum items to render | |
|
| No | Number of items to skip | |
|
| No | Template repeated for each item | |
|
| No | Style for the container element | |
|
| No | Custom label in the editor structure tree | |
| `boolean | object | string` | No | Conditional rendering expression |
Collection-only properties (ignored when sourceType is "prop"):
Property | Type | Description |
|---|---|---|
| `string | string[]` | Direct item IDs or template expression for referenced items |
| `FilterCondition | FilterCondition[] | Record` | Filter conditions |
| `SortConfig | SortConfig[]` | Sort configuration |
|
| Exclude the current CMS page item from results |
|
| Emit a |
Examples
List from component prop:
{
"type": "list",
"sourceType": "prop",
"source": "items",
"children": [
{ "type": "node", "tag": "div", "children": "{{item.label}}" }
]
}List from CMS collection with sorting:
{
"type": "list",
"sourceType": "collection",
"source": "posts",
"limit": 10,
"sort": { "field": "createdAt", "order": "desc" },
"children": [
{
"type": "link",
"href": "{{post._url}}",
"children": [
{ "type": "node", "tag": "h3", "children": "{{post.title}}" },
{ "type": "node", "tag": "p", "children": "{{post.excerpt}}" }
]
}
]
}When sourceType is "collection", the default item variable is the singularized collection name. For "posts", it becomes {{post.title}}. Override with itemAs:
{
"type": "list",
"sourceType": "collection",
"source": "posts",
"itemAs": "article",
"children": [
{ "type": "node", "tag": "h3", "children": "{{article.title}}" }
]
}Filtered collection list:
{
"type": "list",
"sourceType": "collection",
"source": "posts",
"filter": { "field": "category", "operator": "eq", "value": "tech" },
"sort": { "field": "_createdAt", "order": "desc" },
"limit": 5,
"excludeCurrentItem": true,
"children": [
{ "type": "node", "tag": "div", "children": "{{post.title}}" }
]
}List item context variables available in children templates:
Variable | Description |
|---|---|
| Field value from the current item |
| Zero-based index of the current item |
|
|
|
|
6. locale-list (Language Switcher)
Renders a locale switcher that generates links for each configured language. Requires i18n to be configured in project.config.json.
Properties
Property | Type | Required | Default | Description |
|---|---|---|---|---|
|
| Yes | Node type discriminator | |
| `"code" | "name" | "nativeName"` | No |
| How locale text is displayed |
|
| No |
| Show flag icons |
|
| No |
| Include the active locale in the list |
|
| No |
| Show separators between items |
|
| No | Style for the container | |
|
| No | Style for each locale item | |
|
| No | Style for the active locale item | |
|
| No | Style for separators | |
|
| No | Style for flag icons | |
|
| No | Custom label in the editor structure tree | |
| `boolean | object | string` | No | Conditional rendering expression |
Examples
Full language switcher with native names and flags:
{
"type": "locale-list",
"displayType": "nativeName",
"showFlag": true,
"showCurrent": true,
"showSeparator": true,
"style": { "base": { "display": "flex", "gap": "8px", "alignItems": "center" } },
"itemStyle": { "base": { "fontSize": "14px", "color": "var(--text-secondary)" } },
"activeItemStyle": { "base": { "fontWeight": "700", "color": "var(--text-primary)" } }
}Minimal code-only switcher:
{
"type": "locale-list",
"displayType": "code",
"showFlag": false,
"showSeparator": false
}7. slot
Marks where instance children are inserted inside a component structure. Used only in component definitions (components/*.json), not in pages.
Only one slot per component is allowed.
Properties
Property | Type | Required | Description |
|---|---|---|---|
|
| Yes | Node type discriminator |
| `(string | Node)[]` | No | Default content when no children are passed |
Examples
A component structure with a slot:
{
"component": {
"interface": {
"title": { "type": "string", "default": "Card Title" }
},
"structure": {
"type": "node",
"tag": "div",
"style": { "base": { "padding": "16px", "border": "1px solid var(--border)" } },
"children": [
{ "type": "node", "tag": "h3", "children": "{{title}}" },
{ "type": "slot" }
]
}
}
}Slot with default content:
{
"type": "slot",
"default": [
{ "type": "node", "tag": "p", "children": "Default slot content" }
]
}Shared Properties
All node types (except slot) support these properties:
Property | Description |
|---|---|
| Conditional rendering. Accepts |
| Custom display name shown in the editor's structure tree instead of the default. |
| Responsive style object. See Style Properties. |
| CSS pseudo-state rules. See Style Properties. |
| HTML attributes passed through to the rendered element. |
Next Steps
Component Props -- prop types and interpolation
Style Properties -- responsive styles, interactive styles, and conditionals
Template Expressions -- mustache syntax in all contexts
CMS Fields -- field types for CMS collections