Getting Started

Install Regor, mount your first reactive view, and try it live.

Regor binds runtime behavior directly to DOM you already have, or to template content you provide at mount time.

This means you can start from static HTML, mount only where needed, and scale to multiple independent runtime islands on the same page.

01 / InstallAdd Regor

Use your package manager or start with a browser module.

02 / MountChoose a root

Bind existing HTML or supply a template for your app.

03 / InteractConnect state

Use refs and events to make your view respond.

Install

npm install regor
yarn add regor

Quick Start (TypeScript)

Add a mount target to your HTML, then run your TypeScript entry after that element exists (for example, with a module script).

<div id="app"></div>
Your first reactive viewLive Regor
Change state. Watch the DOM.

The buttons update a ref. Regor updates the text bound to it.

YOUR FIRST REF / COUNT 0

One ref, an event handler, and a text binding.

import { html, ref } from 'regor'

export function createCounter(interactive = false) {
  const count = ref(0)
  return {
    interactive,
    count,
    increment: () => count(count() + 1),
    reset: () => count(0),
  }
}

export const counterTemplate = html` <div class="guide-demo guide-demo--split">
  <div class="guide-controls">
    <strong>Change state. Watch the DOM.</strong>
    <p>The buttons update a ref. Regor updates the text bound to it.</p>
    <div class="guide-session-bar">
      <button type="button" @click="increment" :disabled="!interactive">
        Increment
      </button>
      <button type="button" @click="reset" :disabled="!interactive">
        Reset
      </button>
    </div>
  </div>
  <div class="guide-readout">
    <span class="guide-kicker">YOUR FIRST REF / COUNT</span>
    <output
      class="guide-total"
      aria-label="Counter value"
      aria-live="polite"
      r-text="count"
    ></output>
    <p>One ref, an event handler, and a text binding.</p>
  </div>
</div>`
import { createApp, useScope } from 'regor'
import { createCounter, counterTemplate } from './counter'

const element = document.getElementById('app')
if (element) {
  const app = createApp(
    useScope(() => createCounter(true)),
    { element, template: counterTemplate },
  )

  // When this root is no longer needed:
  // app.unbind()  // Stop bindings and listeners, keeping the DOM.
  // app.unmount() // Stop bindings and listeners, removing the root.
}

Click Increment, then Reset. Open the source tabs to see the state, template, and mount code used by this preview.

A minimal app in one file Use the #app root above with this standalone TypeScript example.
import { createApp, html, ref } from 'regor'

const app = createApp(
  {
    count: ref(0),
    inc() {
      this.count(this.count() + 1)
    },
  },
  {
    element: document.querySelector('#app')!,
    template: html`
      <section>
        <button @click="inc">Increment</button>
        <p>Count: <span r-text="count"></span></p>
      </section>
    `,
  },
)

// optional teardown
// app.unbind()
// app.unmount()
The root must exist before you mount

Regor binds to the element you select. Make sure its selector matches your HTML and that the element is present when createApp runs.

CDN ESM

<div id="app"></div>
<script type="module">
  import {
    createApp,
    ref,
  } from 'https://unpkg.com/regor/dist/regor.es2022.esm.prod.js'

  createApp(
    {
      message: ref('Hello from CDN'),
    },
    {
      element: document.querySelector('#app'),
      template: '<h1 r-text="message"></h1>',
    },
  )
</script>

Core Mount Modes

  1. Bind existing markup in place:
createApp({ userName: ref('Ada') }, { selector: '#profile-island' })
  1. Replace root content from template string:
createApp(
  { title: ref('Home') },
  {
    selector: '#app',
    template: '<h1 r-text="title"></h1>',
  },
)
  1. Replace root content from JSON template:
createApp(
  { label: ref('Save') },
  {
    element: document.querySelector('#app')!,
    json: { t: 'button', a: { 'r-text': 'label' } },
  },
)

Reactivity Basics

ref for values and deep object conversion:

import { ref } from 'regor'

const count = ref(0)
count(1)
console.log(count())

sref for shallow object state:

import { sref } from 'regor'

const user = sref({ name: 'Ada', age: 30 })
user().name = 'Grace'
user({ ...user(), age: 31 })

Inside templates, refs are auto-unwrapped, so use count, user.name, not count() or .value.

Shallow state needs an explicit update

With sref, editing a plain nested property does not notify bindings by itself. Replace the object, as in the example above, to update the view.

Component Quick Example

import { createApp, defineComponent, ref } from 'regor'

const UserCard = defineComponent('<article><h3 r-text="name"></h3></article>', {
  props: ['name'],
  context: (head) => ({
    name: head.props.name ?? 'Anonymous',
  }),
})

createApp({
  components: { UserCard },
  activeName: ref('Ada Lovelace'),
})
<UserCard :name="activeName"></UserCard>

Template Syntax You Will Use Daily

  1. r-text="expr" for text.
  2. :attr="expr" or r-bind:attr="expr" for attributes.
  3. .prop="expr" or :prop.prop="expr" for DOM properties.
  4. @event="handler" for events.
  5. r-if / r-else-if / r-else for conditional branches.
  6. r-for="item, #i in items" for loops.
  7. :context="{ ... }" / r-context="{ ... }" for object-style component input.
  8. {{ expr }} and [[ expr ]] interpolation (enabled by default).

Where To Go Next

Overview

See how Regor connects state, templates, and the DOM.

Explore overview

Guide

Explore the concepts with more live examples.

Explore guide

Directives

Find the bindings for lists, forms, attributes, and events.

Explore directives

API Reference

Look up function signatures and usage details.

Explore api reference

Guide: Mounting

Bind existing markup and compose independent islands.

Explore guide: mounting