A template script
written in your markup

Put h-scope on an element and a scope starts there. The attributes inside it bind values to the screen. You start with one script tag and no build step.

If you know Vue, you can already read it.

Expressions are plain Vue, and only the prefix is h-. Reactivity comes from Vue's own core library (@vue/reactivity). You write it straight into markup, with no component files and no build.

Related h-model h-for h-show @click

Nothing to declare. A value exists once you use it.

You do not need to write values down in advance. The input value the server rendered becomes the initial value as is. {{ }} in text is read only directly under the element where h-text-inline is set. Here, that is the button.

Related h-scope h-model :disabled h-text-inline

A scope is a boundary. You write down what it receives.

An inner scope does not see outer values on its own. Write what you pass down with h-provide, and what you receive with h-inject. Wherever you insert a fragment, the markup shows what it depends on.

Related h-provide h-inject h-inherit

When to use it

hyper-scope adds behavior to pages the server rendered.

It fits when

  • The server renders the page ERB · Hono/JSX · JSP · Jinja. Whatever the template language, you add behavior to the HTML
  • You already know Vue's syntax You use @click, :class and h-for as they are
  • The markup shows what the markup depends on It helps you stay in the HTML instead of going back and forth to the JS
  • You do not want bundling You start with one script tag and write directly in the markup

It does not fit when

  • You write your logic mostly in scripts The HTML itself is the data, and this library works on top of it
  • You expect an SPA This library extends the traditional web environment
  • The CSP does not allow unsafe-eval Projects where security matters may not allow this configuration
  • Type checking and unit tests matter The code is text inside markup, so type checkers and test tools do not reach it

Simple.

Light.

On top of server-rendered HTML.

The server renders the page, and the browser only adds behavior on top. A fragment inserted later comes alive on its own if it carries a scope. All there is to learn: 22 attributes, 12 properties, and 2 functions.

Preview

If you have used Vue or Alpine, the table below and a few examples are enough. There are 22 attributes, 12 properties, and 2 functions in all, and each one is explained in the docs.

What it doesVueAlpinehyper-scope
Where values livedata() · setup()x-datah-scope
Text{{ }} · v-textx-texth-text · h-text-inline
Attributes · events:class · @click:class · @click:class · @click
Inputv-modelx-modelh-model
Conditions · loopsv-if · v-forx-if · x-forh-if · h-for
Show and hidev-showx-showh-show
Computed valuecomputedgetterh-computed · getter
Work to run when a value changeswatchEffectx-effecth-effect
Watching one valuewatch$watchNone
Pointing at an elementrefx-ref · $refsh-ref · $refs
Notifying upward$emit$dispatch$emit · $dispatch
Handing downprovide · injectthe outer x-data is visibleh-provide · h-inject
Receiving server valuespropswritten in x-datah-props (JSON)

Three differences from what you know

Where values live

h-scope opens a scope. Values from the server are received with h-props and only read through $props. h-state creates a separate reactive value space inside that element without creating a scope host. Use it to give each row its own values.

→ h-scope · h-state · h-props

Drawing on screen

Text is h-text. To put a value inside text, use h-text-inline and {{ }}. Attributes are :, showing and hiding is h-show, adding and removing is <template h-if>, and repeating is h-for.

→ From h-text to h-for

Input and events

h-model keeps an input and a value in sync, and @ listens for events. Modifiers (.prevent, .trim) are the same as in Vue. Name an element with h-ref and reach it through $refs.

→ h-model · h-on · h-ref

Between scopes

Write what you hand down with h-provide, and what you receive with h-inject. A received name is read-only. You can change the inside of a received object. If the value itself must be replaced, ask the providing side with $emit.

→ h-provide · h-inject · h-inherit

Computed values and work to run

h-computed:name is a computed value read inside that element. h-effect runs again whenever the values it reads change. With a modifier it follows a moment, not values: .mounted, .unmounted, .sealed.

→ h-computed · h-effect

Even when the server renders again

Even when the server sends a fragment again, h-keep carries over the values being typed. h-cloak hides the element until it is mounted, h-await shows based on the state of an async task, and h-pre leaves everything inside untouched.

→ h-keep · h-cloak · h-await · h-pre

What you call from a script

There are two functions. start() mounts the scopes in the document, and plugin() adds names, attributes, and components. Form validation $v and the turbo-frame handle $tf are plugins too.

→ Extensions