State
State is one of the core building blocks in Ornata. It is designed to work well with HTML-first markup, progressive enhancement, and direct component updates.
State can start in more than one place
Section titled “State can start in more than one place”Ornata can build a component’s initial state from:
defaultvalues in the component definitiondata-*values on the root HTML elementinitialStatepassed tomount()
That makes state flexible in an HTML-first environment because a server template, CMS, or other markup source can provide initial values while JavaScript still refines or overrides them at run time.
Initial state precedence
Section titled “Initial state precedence”When Ornata resolves initial state, later sources win.
The order of priority is (lowest to highest):
- Component definition defaults
- Root element
data-*attributes initialStatepassed tomount()[Highest Priority]
That means mount-time JavaScript wins over HTML, and HTML wins over definition defaults.
Ornata automatically maps kebab-case HTML data attributes to your camelCase state properties:
<section data-counter data-count="5" data-label="Server count"></section>const Counter = defineComponent({ state: { count: { default: 0, type: Number }, label: { default: 'Clicks', type: String }, },});
Counter.mount('[data-counter]', { count: 10,});interface CounterState { count: number; label: string;}
const Counter = defineComponent<{ state: CounterState;}>({ state: { count: { default: 0, type: Number }, label: { default: 'Clicks', type: String }, },});
Counter.mount('[data-counter]', { count: 10,});The mounted instance starts with:
count = 10label = "Server count"
State is reactive
Section titled “State is reactive”When state changes after mount, Ornata runs its update flow automatically.
That includes:
- Validates the new value
- Recalculates
computedvalues - Triggers UI render callbacks
- Fires matching
watchhooks - Notifies external state listeners
For the full sequence, see State Update Flow.
This means state updates drive the component directly. To update the state and trigger an update, assign a new value directly like this:
methods: { increment() { this.state.count += 1; },}The same goes for external updates on the public state:
const instance = Counter.mount('[data-counter]');
instance.state.count += 1;Reacting to state changes
Section titled “Reacting to state changes”Ornata gives you two different ways to react to state changes:
watchfor internal component-side reactionsaddStateListener()for external subscriptions on a mounted instance
Use watch when the component itself needs to respond to its own updates.
Use addStateListener() when code outside the component needs to observe public state changes.
Read Watchers and State Listeners for the deeper guidance.
Public state safeguards
Section titled “Public state safeguards”Ornata also protects state access at the component boundary.
Each state property can define:
typevalidates and describes the expected runtime value typeprivatehides the property from external reads and writes on the mounted public statereadonlyallows external code to read the property but prevents external writes
In practice, those safeguards might look like this:
state: { count: { default: 0, type: Number }, token: { private: true }, // `instance.state.token` equals `undefined` externally label: { default: "Clicks", readonly: true }, // `instance.state.label = 'New'` errors and is ignored}These options support a few useful guarantees:
- invalid values can be reported
- private state cannot be read or written externally
- readonly state cannot be written externally
HTML parsing behavior
Section titled “HTML parsing behavior”When Ornata reads state from HTML, it uses the default and type state properties to infer the expected value type. If it can infer the type, it parses the HTML string into that type automatically. If it cannot, Ornata logs a warning and falls back to treating the value as a string.
Depending on the configuration, Ornata can parse values as string, number, boolean, array, or object. For arrays and objects, the HTML value must be valid JSON.
When the built-in parsing behavior is not a good fit, use parse() to define custom parsing logic. For example, if you want to convert a comma-separated string into an array, you can do this:
<section data-search data-filters="red,blue,green"></section>state: { filters: { type: Array, parse(value) { return value.split(","); }, },}A good mental model
Section titled “A good mental model”Ornata state is:
- flexible at initialization time
- direct to update
- reactive once mounted
- guarded at the public boundary
That makes it a strong fit for HTML-first environments that need interactive behavior without giving up control over where the initial data comes from.