Getting started
There's no npm package or official CDN yet — Ultima is used by including the source files directly, as native ES modules. That's how the project itself is used internally.
Before you start
You don't need to know any framework. You do need the basics of HTML, CSS and JavaScript (variables, functions and classes) and a modern browser — Chrome, Edge, Firefox or Safari. Ultima installs nothing: no Node.js, no npm, no build tool. The only extra you'll use is one command to serve your files (step 4).
These are the words you'll meet in the docs, in plain language:
Web Component
An HTML tag you create yourself, like <my-counter>, that
bundles its own markup, style and behavior. It's a browser standard, not a library.
Custom Element
The browser feature behind a Web Component: it lets you register a new tag name and tie a JavaScript class to it.
Shadow DOM
A private area inside a component: its CSS doesn't leak out, and the page's CSS doesn't leak in. It's optional in Ultima.
ES module
A .js file that shares code with other files through
import and export. Browsers understand
it natively with <script type="module">.
Reactive
When the data changes, the screen updates by itself. You change
state and Ultima takes care of the page.
Template
The component's HTML file, where data-* attributes say which
piece of data goes where.
1. Get the core files
Copy (or clone the repository and reference) the two files that make up the framework's core:
src/component_base.js
src/reactive_component.js
No other file is required — that's the entire framework.
2. Create the component's template and class
Every component has two files: an .html file (the template) and a
.js file (the class, which extends
ReactiveComponent when it needs data binding, or
ComponentBase when it doesn't).
<div>
Total: <span data-bind='{"textContent":"total"}'></span>
<button id="increment">+1</button>
</div>
The data-bind attribute says "put the value of total
from the state inside this span". You never write code to update it:
when total changes, the text changes.
import { ReactiveComponent } from './reactive_component.js';
export class MyCounter extends ReactiveComponent {
constructor() {
super(
{ templateUrl: './my-counter.html', shadowDom: true },
import.meta.url
);
}
// Called once this component (and any descendants) finish loading — see the Guide
onLoad() {
super.onLoad();
this.state = { total: 0 };
this.rootNode.querySelector('#increment')
.addEventListener('click', () => {
this.state = { total: this.state.total + 1 };
});
}
}
customElements.define('my-counter', MyCounter);
In short: the constructor tells Ultima where the template is, onLoad()
runs when the template is ready (it sets the starting state and the button's click), and the
last line registers the <my-counter> tag in the browser. Tag names
must contain a hyphen.
3. Use the component
<script type="module" src="./my-counter.js"></script>
<my-counter></my-counter>
4. Run it
Browsers don't load template files when you double-click an HTML file (the
file:// address). Serve the folder with any static server instead. If
you have Python, open a terminal in your project folder and run:
python3 -m http.server
Then open http://localhost:8000 in the browser and click your page.
Without Python, the "Live Server" extension for VS Code does the same job.
F12 and look at the Console
and Network tabs. A 404 on the .html template usually means the
templateUrl path is wrong — remember it is relative to the component's
.js file.
python3 -m http.server, for example) and open it in the browser.
Paths in templateUrl are resolved relative to the component's own
.js file (via import.meta.url), not
relative to the page — so components are independent of wherever they're used.