HyperStandard
import { $, h as html, on } from "hstd"
const Component = () => {
const count = $(0);
return html`
<h1>Count is ${count}</h1>
<button ${{ [on.click]: () => count.$++ }}>
Add more!
</button>
`;
}
document.body[html] = Component();hstd = HyperStandard is a minimal JavaScript library to build fast, interactive, extensible web interface. Visit live demo.
npm create hstd my-app
cd my-app
npm install
npm run devUse --ts for TypeScript with @hstd/ts IntelliSense:
npm create hstd my-app --tsnpm create hstd my-appnpm i @hstd/stdimport { $, h as html } from "https://hstd.io";{
"imports": {
"@hstd/std": "https://hstd.io"
}
}import { $, h as html, on, css } from "@hstd/std"
const buttonClass = $((alertText) => ({
[css]: {
color: "white",
backgroundColor: "blue",
},
[on.click]: () => alert(alertText)
}))
const Main = () => {
const count = $(0);
return html`
<button ${{ [on.click]: () => count.$++, [buttonClass]: "hi" }}>
I'm styled ${count}!
</button>
`
}import { $, h as html, io } from "@hstd/std"
const Linked = () => {
const valueHolder = $(0)
return html`
<h1>these are linked!</h1>
<input ${{ [io.value]: valueHolder, type: "range" }}>
<input ${{ [io.value]: valueHolder, type: "range" }}>
<label>value is ${valueHolder}</label>
`
}const Canvas = () => {
const colorSwitch = $(true);
return html`
<canvas ${{ id: "color", [on.click]: () => colorSwitch.switch() }}></canvas>
`.on(({ color }) => {
const ctx = color.getContext("2d");
colorSwitch.into($ => $ ? "red" : "blue").watch($ => {
ctx.fillStyle = $;
ctx.fillRect(0, 0, 100, 100);
});
})
}import { $, h as html, io } from "@hstd/std";
const Iterated = async function*() {
const
user = $(''),
{ promise, resolve } = Promise.withResolvers()
;
yield html`
<label>Show user <input ${{ [io.value]: user }}/></label>
<button ${{ [on.click]: resolve }}>submit</button>
`;
await promise;
yield html`
<label>Loading...</label>
`;
const { name, age, link } = await fetch(`/api/user/${user.$}`).then(res => res.json());
yield html`
<div>
<label>${name}</label>
<label>${age}</label>
<label>${link}</label>
</div>
`;
}
document.body[html] = Iterated();import { $, h as html, on, io } from "@hstd/std"
const TodoApp = () => {
const todos = $(["Buy milk", "Walk dog"]);
const input = $('');
return html`
<ul>${todos.into(item => html`<li>${item}</li>`)}</ul>
<input ${{ [io.value]: input }}>
<button ${{ [on.click]: () => { todos.push(input.$); input.$ = ''; } }}>
Add
</button>
`
}$([...]) creates an ArrayPointer that tracks mutations (push, pop, shift, unshift, splice, sort, reverse, swap, set) and updates the DOM automatically. Derived queries like find, includes, some, every, reduce return reactive Pointers.
import { $, h as html, css } from "@hstd/std"
const Animated = () => {
const rotation = $(0);
const scale = $(1);
const transform = $`rotate(${rotation}deg) scale(${scale})`;
return html`
<div ${{ [css.transform]: transform }}>Hello</div>
`
}$`...` creates a Pointer that interpolates reactive values into a string. When any interpolated Pointer changes, the string updates automatically.
import { $, h as html, css } from "@hstd/std"
const Themed = () => {
const primary = $("royalblue");
return html`
<div ${{
[css]: {
backgroundColor: primary,
color: $.this.backgroundColor,
borderColor: $.this.color,
border: "2px solid",
}
}}>
color follows backgroundColor
</div>
`
}$.this.propertyName creates a DeferredPointer that references another property within the same attribute object. The reference is resolved at render time.
import { $, h as html, io } from "@hstd/std"
const Dashboard = () => {
const query = $('');
const debounced = query.timeout(300);
const status = debounced.into(q => q ? `Searching: ${q}` : "Type to search");
return html`
<input ${{ [io.value]: query, placeholder: "Search..." }}>
<p>${status}</p>
`
}Pointers support chained derivations: .into(fn), .not(), .bool(), .isit(ifTrue, ifFalse), .timeout(ms), .until(value), .sum(n), .sub(n), .mul(n), .div(n), .mod(n), .is(v), .seq(v), .or(v), .and(v).
hstd validates bindings at runtime and throws descriptive errors for common mistakes:
// Position mismatch
html`<div>${{ color: "red" }}</div>` // Error: Object literal in body position
html`<div ${"hello"}>text</div>` // Error: string in attribute position
// Type mismatch
html`<div ${{ [on.click]: "str" }}>...` // Error: on.click requires a function
html`<div ${{ [css.color]: () => {} }}>…` // Error: css.color requires a string, number, or Pointer
html`<input ${{ [io.value]: "str" }}>…` // Error: io.value requires a Pointer
// Element mismatch
html`<div ${{ [io.value]: ptr }}>…` // Error: io requires input/textarea/select/contenteditableHyperStandard standard library — reactive primitives ($, Pointer, ArrayPointer), DOM templating (h), and declarative bindings (on, css, io).
TypeScript language service plugin for HyperStandard. Editor-agnostic IntelliSense that works with VS Code, vim, neovim, Helix, Zed, and any TypeScript-compatible editor:
- HTML element completion inside
h/htmltagged templates - CSS property completion after
css.and inside[css]: { } - DOM event completion after
on.and inside[on]: { } - IO property completion after
io. $.thisproperty completion with sibling property suggestions- Static diagnostics for type mismatches, position mismatches, and invalid
ioelement targets
HyperStandard-to-WebComponents adapter.
Scaffold a Vite + HyperStandard project with function components, css bindings, HMR, and light/dark theme support.
npm create hstd my-app # JavaScript
npm create hstd my-app --ts # TypeScript + @hstd/tsTextMate grammars (VS Code, Sublime Text) and Tree-sitter queries (neovim, Helix, Zed) are available in pkg/vscode and pkg/tree-sitter-hstd.
hstd is MIT licensed.