From an empty folder to a running Cascade app, with a logotype and a counter - this one, running right here:
Edit HelloWorld.js and save - the page follows.
Any bundler that handles ES modules will do - here, a fresh Vite project. One package brings in the rest of Cascade with it:
npm create vite@latest hello-cascade -- --template vanilla
cd hello-cascade
npm install @liquefy/cascade.uiYou can delete what Vite put in src/ as an example - counter.js, style.css and assets/.
Replace index.html with this - all it needs is an element for the app to render into:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hello Cascade</title>
</head>
<body style="margin: 0; padding: 24px; font-family: sans-serif;">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>Two things tie an app to the page. The render target is where it all goes: here, the #app element. The service locator, provided to every component through the render context, is where components get what they build with - here, the basic theme, providing a themed widget when they ask for button(). Nothing in an app names a theme: change the service locator, and the whole app changes with it.
In src/main.js:
import { RenderContext } from "@liquefy/cascade.component";
import { DOMElementTarget } from "@liquefy/cascade.dom";
import { basicTheme } from "@liquefy/cascade.ui";
import { HelloWorld } from "./HelloWorld.js";
// The render target: where it all goes - the #app element in index.html.
const target = DOMElementTarget.forElement(document.getElementById("app"));
// The service locator - here, the basic theme: it provides the themed
// widgets your components ask for (button(), card(), ...). HTML elements
// (div(), h1(), ...) are real DOM elements unless a locator says otherwise.
new HelloWorld().establish().renderOnto(target, new RenderContext({ serviceLocator: basicTheme }));In src/HelloWorld.js - the app at the top of this page, as it is. initialState() sets up its state; build() describes what it shows, and runs again whenever something it read changes - only what actually changed is updated in the page. Each run's result is matched to the previous one - the same kind of component in the same place is the same component - so its state and its elements are kept. Only what can move, appear or disappear among its siblings - the items of a list - needs a key.
import { Component, callback } from "@liquefy/cascade.component";
import { h1, img, p, text } from "@liquefy/cascade.dom";
import { button, column } from "@liquefy/cascade.ui";
export class HelloWorld extends Component {
// State: set up once, then changed by the user - here, by the button.
initialState() {
return { count: 0 };
}
// Runs again whenever something it read changes (this.count): only what
// actually changed is updated in the page.
build() {
return column(
{
style: {
alignItems: "center", gap: "16px", padding: "40px 24px", borderRadius: "12px",
background: "#1f2d3b", color: "#e6eef6", textAlign: "center",
},
},
img({
src: "https://erobwen.github.io/liquefy/cascade-logo.svg",
alt: "Cascade",
style: { width: "100%", maxWidth: "320px" },
}),
h1({ style: { margin: 0 } }, text("Hello Cascade")),
button(text("Count is " + this.count), callback("count", () => { this.count++; })),
p({ style: { margin: 0, opacity: 0.75 } }, text("Edit HelloWorld.js and save - the page follows.")),
);
}
}
npm run devOpen the address it prints - typically http://localhost:5173 - and count.
Try the Material theme: install it, and render with it instead of the basic one - the same app, every widget replaced.
npm install @liquefy/cascade.ui.materialimport { materialTheme } from "@liquefy/cascade.ui.material";
new HelloWorld().establish().renderOnto(target, new RenderContext({ serviceLocator: materialTheme }));Using icons (icon(), iconButton())? Link the icon fonts the themes draw them with, in index.html's head:
<!-- Material Symbols: the basic theme's icons. Material Icons: the Material theme's. -->
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />Every page of this demo has a button in the top bar showing its own code - there's a lot more to see: layout from real measurements, animations, routing, portals, themes and their colors. And each package has a README of its own, from the repository's on.