Getting Started
This guide takes you from installation to a working progressively enhanced component in an HTML-first environment.
Install
Section titled “Install”npm install ornataIf you want to enhance a page without a bundler, load the browser build from a CDN instead:
<script src="https://cdn.jsdelivr.net/npm/ornata@latest/dist/index.global.js"></script><script> const { defineComponent } = window.Ornata;</script>Pin a specific version in production so your deployed HTML always gets the same runtime.
Start with HTML
Section titled “Start with HTML”Write server-rendered markup that already makes sense on its own.
Ornata treats that markup as the integration surface, then layers a reusable component on top.
<section data-counter> <h2>Counter</h2> <p> Count: <span data-count-value>0</span> </p> <button type="button" data-count-button>Increment</button></section>Define a component
Section titled “Define a component”import { defineComponent } from "ornata";
const Counter = defineComponent({ name: "Counter", state: { count: { default: 0 }, }, elements: { value: { query: "[data-count-value]" }, button: { query: "[data-count-button]" }, }, methods: { increment() { this.state.count += 1; }, }, render: { value() { return { text: String(this.state.count), }; }, button() { return { events: { click: () => this.methods.increment(), }, }; }, },});import { defineComponent } from "ornata";
interface CounterState { count: number;}
interface CounterElements { value: Element | null; button: Element | null;}
interface CounterMethods { increment(): void;}
const Counter = defineComponent<{ state: CounterState; elements: CounterElements; methods: CounterMethods;}>({ name: "Counter", state: { count: { default: 0 }, }, elements: { value: { query: "[data-count-value]" }, button: { query: "[data-count-button]" }, }, methods: { increment() { this.state.count += 1; }, }, render: { value() { return { text: String(this.state.count), }; }, button() { return { events: { click: () => this.methods.increment(), }, }; }, },});Mount it
Section titled “Mount it”const root = document.querySelector("[data-counter]");
if (root) { Counter.mount(root);}const root = document.querySelector("[data-counter]");
if (root) { Counter.mount(root);}What happens when it mounts
Section titled “What happens when it mounts”When mount() runs, Ornata:
- resolves the root element
- reads and prepares state
- resolves configured elements
- binds methods to the internal component instance
- runs the mount lifecycle hook if present
- performs an initial render pass for each state property
That state can come from component defaults, HTML data-* attributes on the root element, or an initialState object passed to mount().
Together, those pieces form a small component contract: the HTML stays visible, the state has a clear home, and the enhancement logic remains reusable.
Where to go next
Section titled “Where to go next”- Read Your First Component for a deeper walkthrough
- Read State to understand initialization, reactivity, and safety controls
- Read Page Bootstrap to mount components declaratively with
data-ornata - Read Component Anatomy for the full shape of
defineComponent()