Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


A simple JavaScript library for creating HTML UI, inspired by ReactJS and created for fun, and science, of course.

Build Coverage Version Dependencies

Quick links

  1. Ideology
  2. Concepts
  3. API
  4. Helpers
  5. Examples
  6. Utility
  7. Made With


The idea of a UI rendering library is that a client should be responsible for rendering its own UI and the server should not be aware of the presentation logic, transmitting only essential data.

The main goal behind luri is simplicity. It is designed in a way that requires as little learning as possible. If you're familiar with JavaScript and HTML it should literally take you no more than 10 minutes before you can start building. Second but equally as important is the simplicity of the source code. It is ~1.7KB minified and gzipped.


There are a few simple concepts you need to understand before you can use luri.

  • Definitions
    A definition is a piece of information that can be used by the library to construct an HTML element. The most common data type for definitions is an object which contains the HTML element's attributes as properties, however other valid definitions are strings, numbers, null, HTMLElements, Promises and Components, which are another concept, explained below. Arrays are also considered a valid definition, however they represent a list of definitions and do not provide information for a single HTML element, so use with caution.

  • Components
    A component is a class that inherits from luri.Component. Every component must implement a props() method, which must return a definition that will tell luri how to construct that particular component. Once constructed, there is a bond created between the Component and the HTMLElement. Components are useful for code separation. They can also listen globally to emitted events and react to each accordingly.

  • Events
    Events in the context of the library are quite different than DOM events. They do not propagate but rather get dispatched to all components (by default) which define listeners and react only to events they care about. It would probably be more accurate to categorize it as a pub-sub rather than event system but meh.


  • luri.construct: constructs an HTMLElement or Text node from the provided input definition.
    luri.construct(definition: definition): HTMLElement | Text
  • luri.emit: emits an event to all currently attached to the document Components
    luri.emit (event: string, any[]): data: any[]
  • luri.dispatchToClass: emits an event to all currently attached to the document Components matching className
    luri.dispatchToClass(className: string, event: string, any[]): data: any[]
  • luri.dispatchTo: emits an event to a collection of HTMLElement nodes that reference Components
    luri.dispatchTo(collection: HTMLCollection | NodeList, event: string, any[]): data: any[]
  • luri.promise: allows for a custom placeholder element until promise is resolved
    luri.promise(def: definition, promise: Promise): def: definition


There are helper functions for every standard HTML tag that modify a definition, by adding the node property automatically. Helper functions can be accessed via luri.<ANY_HTML_TAG_IN_UPPERCASE>(<Definition>).


In the examples below #text means the output is a Text node and html markup represents HTMLElement instances, output is never a string.

  • Simplest usage - live


    #text "Hi"

  • Creating an element - live

     node: "span"


  • With attributes and content - live

      node: "h1",
      class: "title",
      html: "Hello"

    <h1 class="title">Hello</h1>

  • Nesting - live

      node: "p",
      html: {
        node: "img",
        src: "..."

    <p><img src="..."></p>

  • With multiple children - live

      node: "p",
      html: [
          node: "img",
          src: "..."

    <p>Hey<img src="..."></p>

  • Event listeners - live

      node: "button",
      onclick() { 


    Event listeners are assigned to the on* properties of HTMLElement instances so are not visible in the markup.

  • Promises - live

      "The time is: ",
        .then(response => response.json())
        .then(time => ({
          node: "strong",
          html: time.datetime
        })).catch(() => "Error fetching time")

    <div>The time is: <div></div></div>

    By default, luri places an empty div as a placeholder for the Promise result. As soon as the promise gets resolved, the DOM changes:

    <div>The time is: <strong>2020-09-01T08:00:00.000000+01:00</strong></div>

    You can use luri.promise if you need a custom placeholder.

  • Components

    A slightly more complex example using a component can be found here.

You can browse ./examples for more demos but beware. They were added a long time ago, eventually they will get updated if there is interest in the library, but the working principle is the same.

You can check out the spa-quickstart repository that will get you started with building a single page web app in no time.


You will find a transpiler in ./utils/transpiler/index.html that you can use to convert an HTML string into a definition. You can also access it here, thanks to github pages.

Made With

Projects made using luri.


No description, website, or topics provided.



No releases published


No packages published