Component Props Reference
Components in Meno are reusable structures with typed interfaces. Each prop in the interface declares its type, default value, and optional configuration. Props are defined in components/*.json and their values are passed via the props object on component node instances.
Prop Types
Type | Description | Editor Control | Default Value Type |
|---|---|---|---|
| Single-line text | Text input |
|
| Numeric value | Number input |
|
| True/false toggle | Checkbox |
|
| Dropdown from options | Select dropdown |
|
| URL with optional target | Link editor |
|
| File path (upload) | File picker |
|
| HTML content | Rich text editor |
|
| Array of structured items | List editor |
|
There is NO "image" type. For images, use file with accept: "image/*".
Type Definitions
string
Single-line text input.
{
"title": { "type": "string", "default": "Hello World" }
}number
Numeric input.
{
"count": { "type": "number", "default": 3 }
}boolean
Toggle switch in the editor.
{
"visible": { "type": "boolean", "default": true }
}select
Dropdown selection from predefined options.
{
"variant": {
"type": "select",
"options": ["primary", "secondary", "ghost"],
"default": "primary"
}
}Select props can also reference project-level enums:
{
"size": {
"type": "select",
"enumName": "sizes",
"default": "md"
}
}link
URL with optional target. The editor shows a link input with target toggle.
{
"cta": {
"type": "link",
"default": { "href": "/", "target": "_blank" }
}
}The value is an object: { "href": "/about", "target": "_blank" }. The target field is optional.
file
File upload. The accept property restricts file types using MIME patterns.
{
"avatar": { "type": "file", "accept": "image/*", "default": "" },
"document": { "type": "file", "accept": "application/pdf", "default": "" }
}rich-text
HTML content edited with a rich text editor.
{
"body": { "type": "rich-text", "default": "<p>Enter content here.</p>" }
}list
Array of structured items. Each item follows a schema defined by itemSchema.
{
"features": {
"type": "list",
"itemSchema": {
"icon": { "type": "file", "accept": "image/*", "default": "" },
"title": { "type": "string", "default": "Feature" },
"description": { "type": "string", "default": "" }
},
"default": [
{ "icon": "", "title": "Fast", "description": "Built for speed" }
]
}
}The itemSchema uses the same prop types as the component interface, except nested list types are not allowed.
Prop Configuration Properties
Property | Applies To | Description |
|---|---|---|
| All | Prop type (required) |
| All | Default value |
|
| Array of allowed values |
|
| Reference to a project-level enum name |
|
| MIME pattern for file type filtering (e.g., |
|
| Record of prop definitions for each list item |
Reserved Names
Never use "children" as a prop name. The children key is reserved for slot content passed to the component instance.
Using Props in Component Structure
Props are referenced in the component structure using {{propName}} template expressions.
Text Interpolation
Use {{propName}} in children to insert prop values as text:
{
"component": {
"interface": {
"title": { "type": "string", "default": "Hello" },
"subtitle": { "type": "string", "default": "World" }
},
"structure": {
"type": "node",
"tag": "div",
"children": [
{ "type": "node", "tag": "h2", "children": "{{title}}" },
{ "type": "node", "tag": "p", "children": "{{subtitle}}" }
]
}
}
}Attribute Interpolation
Use {{propName}} in attribute values:
{
"component": {
"interface": {
"imageSrc": { "type": "file", "accept": "image/*", "default": "" },
"imageAlt": { "type": "string", "default": "" }
},
"structure": {
"type": "node",
"tag": "img",
"attributes": {
"src": "{{imageSrc}}",
"alt": "{{imageAlt}}"
}
}
}
}Style Mappings
Map prop values to CSS values using _mapping objects:
{
"component": {
"interface": {
"variant": {
"type": "select",
"options": ["primary", "secondary"],
"default": "primary"
}
},
"structure": {
"type": "node",
"tag": "button",
"style": {
"base": {
"backgroundColor": {
"_mapping": true,
"prop": "variant",
"values": {
"primary": "var(--primary)",
"secondary": "var(--secondary)"
}
},
"padding": "12px 24px"
}
},
"children": "{{text}}"
}
}
}The _mapping object has three fields:
Field | Type | Description | |
|---|---|---|---|
|
| Marker that identifies this as a style mapping | |
|
| Name of the interface prop to read | |
| `Record<string, string \ | number>` | Map from prop values to CSS values |
Conditional Rendering with Props
Use a mapping in the if property to conditionally render nodes:
{
"type": "node",
"tag": "div",
"if": {
"_mapping": true,
"prop": "showBanner",
"values": { "true": true, "false": false }
},
"children": "This is conditionally rendered."
}Link Mappings
For link nodes, map a link-type prop to the href:
{
"type": "link",
"href": { "_mapping": true, "prop": "cta" },
"children": ["{{ctaText}}"]
}When values is omitted from a link mapping, it acts as a passthrough for link-type props.
Internationalized Prop Values
Prop values can be localized using the _i18n object format:
{
"type": "component",
"component": "Hero",
"props": {
"title": { "_i18n": true, "en": "Welcome", "pl": "Witaj" },
"subtitle": { "_i18n": true, "en": "Get started", "pl": "Rozpocznij" }
}
}The correct value is automatically resolved based on the current locale during rendering.
Component JavaScript and CSS
Components can include custom JavaScript and CSS:
{
"component": {
"interface": {
"duration": { "type": "number", "default": 300 }
},
"structure": {
"type": "node",
"tag": "div",
"children": "Animated element"
},
"javascript": "console.log('Component mounted');",
"css": ".custom-class { transition: all 0.3s ease; }",
"defineVars": true
}
}The defineVars property controls prop injection into JavaScript:
true: all interface props are available as JavaScript variablesstring[]: only specified props are exposedOmitted: no automatic prop injection
Full Component Example
{
"component": {
"interface": {
"title": { "type": "string", "default": "Card Title" },
"image": { "type": "file", "accept": "image/*", "default": "" },
"variant": {
"type": "select",
"options": ["default", "featured"],
"default": "default"
},
"link": { "type": "link", "default": { "href": "#" } }
},
"structure": {
"type": "node",
"tag": "article",
"style": {
"base": {
"borderRadius": "8px",
"overflow": "hidden",
"border": {
"_mapping": true,
"prop": "variant",
"values": {
"default": "1px solid var(--border)",
"featured": "2px solid var(--primary)"
}
}
}
},
"children": [
{
"type": "node",
"tag": "img",
"attributes": { "src": "{{image}}", "alt": "{{title}}" }
},
{
"type": "node",
"tag": "div",
"style": { "base": { "padding": "16px" } },
"children": [
{ "type": "node", "tag": "h3", "children": "{{title}}" },
{ "type": "slot" }
]
},
{
"type": "link",
"href": { "_mapping": true, "prop": "link" },
"children": ["Read more"]
}
]
}
}
}Next Steps
Node Types -- all 7 node types
Style Properties -- responsive styles and mappings
Template Expressions -- mustache syntax reference
Project Config -- component types and categories