Home

Awesome

Tint

A natural template engine for the HTML DOM.

Docs

Showcase

The classic TODO app, with an initial server-rendered state.

<html>
  <head>
    <script type="module">
      import compile from "https://cdn.jsdelivr.net/gh/marcodpt/tint/template.js"
      const render = compile(document.getElementById("app"))

      const state = {
        todos: [
          "read a book",
          "plant a tree"
        ],
        value: "",
        AddTodo: () => {
          state.todos.push(state.value)
          state.value = ""
          render(state)
        },
        NewValue: ev => {
          state.value = ev.target.value
        }
      }

      render(state)
    </script>
  </head>
  <body>
    <main id="app">
      <h1>To do list</h1>
      <input type="text" value:="value" oninput:="NewValue">
      <ul>
        <li each:="todos" text:></li>
      </ul>
      <button onclick:="AddTodo">New!</button>
    </main>
  </body>
</html>

Result:

<main id="app">
  <h1>To do list</h1>
  <input type="text" value="">
  <ul>
    <li>read a book</li>
    <li>plant a tree</li>
  </ul>
  <button>New!</button>
</main>

It looks like a normal template engine, but internally compiles the template to:

({ todos, value, NewValue, AddTodo }) =>
  h("main", {}, [
    h("h1", {}, text("To do list")),
    h("input", { type: "text", oninput: NewValue, value }),
    h("ul", {},
      todos.map((todo) => h("li", {}, text(todo)))
    ),
    h("button", { onclick: AddTodo }, text("New!")),
  ])

where h and text can be any hyperscript function you want to use.

You can use it with these frameworks:

With your help, we can grow this list and improve the work done on already supported frameworks.

With a little trick, you can even render your application on the server side, without the complications of the build steps.

<html>
  <head>
    <script type="module">
      import compile from "https://cdn.jsdelivr.net/gh/marcodpt/tint/template.js"
      const app = document.getElementById("app")
      const render = compile(app)

      const state = {
        todos: Array.from(app.querySelectorAll('li')).map(e => e.textContent),
        value: "",
        AddTodo: () => {
          state.todos.push(state.value)
          state.value = ""
          render(state)
        },
        NewValue: ev => {
          state.value = ev.target.value
        }
      }

      render(state)
    </script>
  </head>
  <body>
    <main id="app">
      <h1>To do list</h1>
      <input type="text" value:="value" oninput:="NewValue">
      <ul>
        <li each:="todos" text:>read a book</li>
        <li not:>plant a tree</li>
      </ul>
      <button onclick:="AddTodo">New!</button>
    </main>
  </body>
</html>

What have you achieved:

To celebrate the widespread happiness, how about taking a look at the documentation.

Docs

To generate the docs and create a server for tests.

mdbook serve

Deno support

Testing tint in deno

deno test --allow-read tests/deno.js

Currently this is the only suported and tested version (deno_dom@v0.1.38)

import {DOMParser} from "https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts";

const parser = new DOMParser()
const document = parser.parseFromString(
  Deno.readTextFileSync('path/to/file.html'),
  "text/html"
)

Philosophy

Contributing

Everything within this documentation is tested here. And it will always like this. Any changes to the documentation, any contributions MUST be present in the tests.

If the tests do not pass in your browser, if you find any bugs, please raise an issue.

Any changes must be within the philosophy of this project.

It's a very simple project. Any contribution is greatly appreciated.

Influences and thanks

This work is hugely influenced by these amazing template engines and frameworks:

A huge thank you to all the people who contributed to these projects.