Skip to content

Component Anatomy

defineComponent() is the main authoring API in Ornata. It is where you describe how a reusable component fits into existing HTML, what it expects from the DOM, and how it reacts over time.

const Component = defineComponent({
name: 'Example',
root: {},
state: {},
elements: {},
lifecycle: {},
watch: {},
methods: {},
computed: {},
data: {},
render: {},
});

You will not use every section in every component, but each one has a clear role.

name sets the display name used in debugging and error reporting.

If you omit it, Ornata falls back to "UnnamedComponent".

root configures settings related to the component’s root element.

It currently supports matches, which validates that the mounted root matches a selector. If it does not, Ornata logs an error to the console so integration mistakes are easier to spot and the component can enforce its expected root element.

root: {
matches: "input",
}

state defines reactive properties for the component.

default, type, and parse shape how a state value is initialized and validated. private and readonly control how public code can interact with it.

A state definition might look like this:

state: {
count: { default: 0, type: Number },
label: { default: "Clicks", readonly: true },
}

State in Ornata can be initialized from component defaults, root HTML data-* attributes, or mount-time initialState. For a focused walkthrough, see State.

elements defines the important DOM references a component uses.

Use query, queryAll, create, or resolve to define how each reference is obtained. Element resolution is scoped to the component root by default, and each entry should use only one of these strategies.

Use min and max when the component needs to enforce structural expectations about how many matching elements must exist.

An elements definition might look like this:

elements: {
button: { query: "[data-count-button]" },
items: { queryAll: "[data-item]" },
}

This is one of Ornata’s most valuable features because it makes DOM resolution an explicit part of the component contract instead of scattering lookups across the implementation. For a dedicated walkthrough, see Elements.

methods defines internal reusable actions.

Methods are bound to the internal instance, so they can safely reference instance data such as this.state, this.elements, this.computed, and this.data.

methods: {
increment() {
this.state.count += 1;
},
}

Methods are useful for keeping render callbacks small and for centralizing named component actions. For a focused walkthrough, see Methods.

computed derives values from state changes.

A computed definition might look like this:

computed: {
hasCount() {
return this.state.count > 0;
},
}

For callback details and usage patterns, see Computed and defineComponent.

watch reacts to state changes.

A watch definition might look like this:

watch: {
count({ isInitial, newValue }) {
if (!isInitial) {
console.log("Updated:", newValue);
}
},
}

For callback details and usage patterns, see Watchers and defineComponent.

data stores additional user-defined values on the internal instance.

Use it for values that do not need to be reactive.

data: {
analyticsKey: "counter",
}

data is useful for persistent internal values like timer IDs, observer instances, caches, and third-party integration objects. For a focused walkthrough, see Data.

render maps resolved elements to DOM updates.

Render keys map directly to the names defined in your elements contract. For example, a value() render callback automatically updates the value element:

render: {
value() {
return {
text: String(this.state.count),
};
},
}

Render callbacks receive context such as index when rendering element arrays, and can return DOM update keys like text, attributes, classes, and events. For a deeper walkthrough, see Render Options and defineComponent.

lifecycle defines setup and cleanup hooks for the component instance.

A lifecycle definition might look like this:

lifecycle: {
mount() {
console.log("Mounted");
},
unmount() {
console.log("Cleaned up");
},
}

mount runs when the component is created, and unmount runs when it is disposed. Lifecycle hooks are best for setup and cleanup work rather than DOM output. For a deeper walkthrough, see Lifecycle and defineComponent.