Documentation Index
Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
Use this file to discover all available pages before exploring further.
MetabindUI Inspector Grammar with Zod Compatibility
Overview
The inspector function defines component properties for both UI editing controls and type validation. This grammar is compatible with Zod schemas and can be used to auto-generate TypeScript types.
Basic Structure
const inspector = () => ({
propertyName: {
title: 'Human-readable title',
type: 'string',
description: 'Optional description of this property',
// Additional type-specific fields
},
// Additional properties...
});
Mapping to Zod
import { z } from 'zod/v4';
function createZodSchema(inspectorDefinition) {
const schemaObj = {};
for (const [key, def] of Object.entries(inspectorDefinition)) {
let schema;
switch (def.type) {
case 'string':
schema = z.string();
if (def.minLength !== undefined) schema = schema.min(def.minLength);
if (def.maxLength !== undefined) schema = schema.max(def.maxLength);
break;
case 'number':
schema = z.number();
if (def.min !== undefined) schema = schema.min(def.min);
if (def.max !== undefined) schema = schema.max(def.max);
break;
case 'boolean':
schema = z.boolean();
break;
case 'color':
schema = z.string().regex(/^#/, { message: 'Must be a valid color string' });
break;
case 'enum':
const values = def.options.map(([v]) => v);
schema = z.enum([...values]);
break;
case 'json':
schema = z.any();
break;
case 'array':
const itemSchema = createZodSchema({ item: def.itemType }).item;
schema = z.array(itemSchema);
if (def.minItems !== undefined) schema = schema.min(def.minItems);
if (def.maxItems !== undefined) schema = schema.max(def.maxItems);
break;
case 'object':
schema = z.object(createZodSchema(def.properties));
break;
default:
schema = z.any();
}
if (def.default !== undefined) {
schema = schema.default(def.default);
} else if (!def.required) {
schema = schema.optional();
}
schemaObj[key] = schema;
}
return schemaObj;
}
// Usage
const zodSchema = z.object(createZodSchema(inspector()));
type MyComponentProps = z.infer<typeof zodSchema>;
Property Types
| Type | UI Control | Zod Equivalent |
|---|
| string | Text input | z.string() |
| number | Number input | z.number() |
| boolean | Toggle | z.boolean() |
| color | Color picker | z.string().regex(/^#/)) |
| enum | Dropdown | z.enum([...]) |
| json | JSON editor | z.any() |
| array | List | z.array(...) |
| object | Object editor | z.object({...}) |
| asset | Media browser | z.string() or z.array(z.string()) |
| components | Component list | z.array(...) |
Common Fields
All property types may include:
title: Human-readable name
description: Description or tooltip
default: Default value
required: Whether the field is mandatory
hidden: Hide from UI editor
deprecated: Mark as deprecated with optional message
group: Group for UI organization
condition: Conditional display rule { key, eq }
Type-Specific Fields
String
{
type: 'string',
default: 'Default text',
placeholder: 'Enter text here...',
multiline: false,
minLength: 0,
maxLength: 100
}
Number
{
type: 'number',
default: 0,
min: 0,
max: 100,
step: 1,
unit: 'px',
slider: true
}
Boolean
{
type: 'boolean',
default: false,
labels: {
true: 'Enabled',
false: 'Disabled'
}
}
Color
{
type: 'color',
default: '#ffffff',
format: 'hex',
alpha: true
}
Enum
{
type: 'enum',
options: [
['value1', 'Display 1'],
['value2', 'Display 2']
],
default: 'value1'
}
JSON
{
type: 'json',
default: { key: 'value' }
}
Array
{
type: 'array',
itemType: { type: 'string' },
default: [],
minItems: 0,
maxItems: 10
}
Object
{
type: 'object',
properties: {
field1: { type: 'string', title: 'Field 1' },
field2: { type: 'number', title: 'Field 2' }
},
default: { field1: '', field2: 0 }
}
Advanced Features
Conditional Properties
{
type: {
type: 'enum',
options: [['simple', 'Simple'], ['advanced', 'Advanced']],
default: 'simple'
},
advancedSetting: {
type: 'string',
condition: { key: 'type', eq: 'advanced' }
}
}
Asset
{
type: 'asset',
title: 'Background Image',
assetTypes: ['image', 'video'], // Optional - defaults to ['image'] if not provided
multiSelect: false, // Optional - defaults to false if not provided
default: '' // Optional - ID of default asset
}
// For multi-selection
{
type: 'asset',
title: 'Gallery Images',
assetTypes: ['image'],
multiSelect: true,
default: [] // Optional - array of asset IDs
}
Custom Controls
{
type: 'custom',
control: 'imagePicker',
controlProps: {
source: 'library'
}
}
Computed Defaults
{
width: {
type: 'number',
default: 100
},
height: {
type: 'number',
default: '@{width}'
}
}
TypeScript Type Generation
interface MyComponentProps {
/** Main heading text */
title?: string;
size?: 'small' | 'medium' | 'large';
showIcon?: boolean;
iconName?: string;
colors?: {
background?: string;
text?: string;
};
padding?: {
top?: number;
right?: number;
bottom?: number;
left?: number;
};
items?: Array<{
label?: string;
value?: string;
}>;
}
Best Practices
- Use descriptive
title and description.
- Group related properties with
group.
- Set sensible
default values.
- Use
condition to improve UI relevance.
- Avoid unused fields.
- Maintain property declaration order.
- Favor predictable, flat object shapes.
- Avoid optional fields unless semantically needed.