Skip to content

jmsapps/ntml

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

67 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NTML Logo

NTML

The next-gen-reactive template markup language.

NTML is a reactive client-side single page application (SPA) renderer written in Nim. It provides a lightweight signal and effect system, and a JSX-like DSL for composing DOM nodes with reactive updates.


Features

  • Signals: reactive primitives for state management.
  • Derived Signals: automatically compute values from other signals.
  • Effects: side effects that run in response to signal changes.
  • DOM Helpers: simple wrappers for element creation and updates.
  • Control Flow: templates for if, case, and loops inside the DSL.
  • Component Props: composable component definitions with inheritance support.
  • Routing: simple and intuitive routing with navigate().
  • Styled Components: reactive styled macro keeps components clean and organized.
  • Form Bindings: built-in bindValue/bindChecked wire signals to form inputs for two-way updates.
  • Lifecycle Cleanup: automatic teardown releases subscriptions, event listeners, and styled classes when nodes unmount.
  • Signal Operators: rich overloads let you compose comparisons and boolean logic directly on Signals.
  • Reactive CSS Vars: the styleVars helper keeps CSS custom properties in step with live signal data.
  • Keyed List Rendering: efficiently reconciles list updates by reusing existing DOM nodes, preserving element identity and minimizing re-renders.

Code Sample

var count: Signal[int] = signal(0)
let doubled: Signal[string] = derived(count, proc (x: int): string = $(x*2))

let component: Node =
  d(id="container"):
    "Count: "; count; br();
    "Doubled: "; doubled; br(); br();

    button(
      type="button",
      onClick = proc (e: Event) =
        count.set(count() + 1)
    ):
      "Increment"

Getting started

Runnable examples are available in the examples directory. First start a server at the project root:

npx serve --single .

Add an index.html file at the project root:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Run Nim-Generated JS</title>
  </head>
  <body>
    <script src="/index.js"></script>
  </body>
</html>

Hello world:

nim js --out:index.js examples/helloWorld.nim

Runnable Examples

  • Hello World (examples/helloWorld.nim): smallest possible component render, useful for sanity-checking your toolchain.
  • Todos (examples/todos.nim): reactive list management with mountChildFor, derived filters, two-way <input> bindings, and dynamic styling.
  • Forms (examples/forms.nim): showcases nested signals, validation hints, and bindValue/bindChecked helpers.
  • Routing (examples/router.nim): leverages navigate() and route signals to orchestrate multipage flows.
  • Styling (examples/styled.nim): demonstrates the styled macro, scoped CSS hashing, and reactive styleVars.
  • Keyed Diffs (examples/keyedDiffs.nim): showcases keyed list rendering, highlighting when entries patch versus remount.
  • Effects (examples/effect.nim): the effect explores the effect API, including cleanup, auto-runners, and delayed updates.
  • Overloads (examples/overloads.nim): comprehensive showcase of signal operator overloads in one live dashboard.

Project Status

This project is still experimental. As such, it is not currently in a state that is deemed ready for a production environment. A roadmap can be found in ROADMAP.md.

About

A reactive, client-side single-page application (SPA) renderer written in Nim.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages