Claude
Skills
Sign in
Back

litejs-ui

Included with Lifetime
$97 forever

Use when building UI with LiteJS framework — writing .ui templates, creating views and routes, using bindings, handling events, i18n, El API, or editing @litejs/ui source code

Design

What this skill does


# LiteJS UI Engine

Dependency-free ES5 UI engine (~25kB). Templates, routing, data binding, i18n, touch gestures — no transpiling/bundling.

Although written in ES5, LiteJS works seamlessly in ESM projects — just include the scripts and start building.

## Template Syntax (.ui files)

Indentation-based hierarchy using CSS selectors. Indent = child, dedent = sibling.

```
h1 My list
ul.green.star
    li
        a[href="#a"] Item A
    li > a[href="#b"] Item B
footer
    button:disabled My button
```

Becomes `<h1>My list</h1><ul class="green star"><li><a href="#a">Item A</a></li>...`.

**Selectors:** `tag#id.class1.class2[attr=value]`. Omitting tag defaults to `div`.
**Child combinator:** `li > a[href="#b"] Item B` — inline child.
**Text content:** bare text after selector becomes element text via i18n: `_(text)`.
**Raw text:** `= text content` — direct text node insertion, no i18n.
**Comments:** `/ comment text` — lines starting with `/`.

## Plugins (% prefix)

| Plugin | Usage | Purpose |
|--------|-------|---------|
| `%view name [parent]` | `%view home #public` | Define routed view |
| `%el name` | `%el Dialog` | Define reusable custom element |
| `%slot [name]` | `%slot footer` | Content placeholder in custom elements |
| `%def routes files` | `%def users/{id} users.js,%.css` | Define route with file dependencies |
| `%css` | `%css` + indented CSS block | Inject inline CSS |
| `%js` | `%js` + indented JS block | Inline JavaScript handlers |
| `%each items` | `%each ["a","b"]` | Replicate template block |
| `%svg name` | `%svg icon` | Define SVG custom element (alias for `%el`) |
| `%start` | `%start` | Trigger app initialization (start routing) |

**View names:** Starting with `#` = container without own route (structural only).
**Custom elements:** After `%el Dialog`, use `Dialog` as a selector in templates.

### Loading Templates

Templates are loaded from `<script type="ui">` tags in HTML:

```html
<script type="ui">
%view home #
  h1 Hello
%start
</script>
<script src="https://litejs.com/litejs.full.min.js"></script>
```

External .ui files: `<script type="ui" src="views.ui"></script>`

## Bindings (; prefix)

Bindings connect data to DOM. Suffix `!` = execute once, don't update.

| Binding | Syntax | Effect |
|---------|--------|--------|
| `;txt` | `;txt expression` | Set text content |
| `;cls` | `;cls "active", condition` | Add/remove CSS class |
| `;css` | `;css "color", value` | Set inline style |
| `;set` | `;set "data-id", id` | Set attribute |
| `;val` | `;val formField` | Two-way form value binding |
| `;if` | `;if condition` | Conditional render (removes/restores element) |
| `;each` | `;each! "item", array` | List iteration, creates subscope per item |
| `;el` | `;el tagName` | Dynamic element type |
| `;ref` | `;ref myRef` | Store element reference in scope |
| `;name` | `;name fieldName` | Set form element name |
| `;view` | `;view url` | Set href for view navigation |
| `;on` | `;on "event", handler` | Attach event listener |
| `;one` | `;one "event", handler` | One-time event listener |
| `;is` | `;is value, "a,10=b,20=c"` | Threshold-based class switching |
| `;d` | `;d text` | Render block-level document markup |
| `;t` | `;t text` | Render inline markup |
| `;xlink` | `;xlink "#route"` | SVG namespace href (`xlink:href`) |
| `$s` | `;$s` | Initialize scope with element attributes |

**Once modifier:** `;txt! value` — bind at render, never re-evaluate.
**Default binding:** Bare text `h1 Hello` becomes `;txt _("Hello",$s)` — auto i18n lookup.
**Unknown bindings** fall through to `;set` (attribute setter). E.g., `;href! url` sets the `href` attribute.
**Separator:** `:` works the same as space: `;txt:value` equals `;txt value`.
**View-level bindings:** Inside `%view`, bindings set view properties. `;f "file.js"` sets file dependencies loaded on navigation.

## Event Shorthand (@ prefix)

```
@click handler              →  ;on! "click", handler
@click! handler             →  ;one! "click", handler
@keyup "navigate", param    →  ;on! "keyup", "navigate", param
```

Event handlers can be strings (emitted on View) or function references.

**Important:** Outside of `%view` blocks, `@click handler` resolves `handler` from the scope chain. Since the scope is `$d` (global scope), the handler function must be on `$d`:

```javascript
%js
    // WRONG — function declaration not accessible from template scope
    function doSomething() { ... }

    // RIGHT — attach to $d so template bindings can find it
    $d.doSomething = function() { ... }
```

## `;val` Binding Details

`;val` is designed for **form-level** two-way binding. Put `;val data` on a `form` element and use `name` attributes on inputs:

```
form
    ;val data
    input[name=email][type=email]
    textarea[name=notes][rows=4]
```

This syncs form values into `$d.data = {email: "...", notes: "..."}`.

**Gotcha:** Using `;val field` on a standalone input/textarea (outside a `form` with `;val`) does **not** reliably sync user input back to the scope variable. For standalone elements, either wrap in a form or read the DOM value directly:

```javascript
var el = document.getElementById("myInput")
var value = el.value
```

## Views and Routes

### Initialization

```javascript
var app = LiteJS()
```

Options only needed when changing defaults:

| Option | Default | Effect |
|--------|---------|--------|
| `home` | `"home"` | Default view name |
| `root` | `document.body` | Root element for views |
| `breakpoints` | — | Responsive breakpoints, e.g. `"sm,601=md,1025=lg"` |
| `locales` | — | Locale definitions, e.g. `{en: "en"}` |
| `globals` | — | Default translations |

Returns View constructor. Available as `$ui` in templates, use chosen variable name (`app`) in plain JavaScript.

### Defining Views

In .ui templates:
```
%view #public #
.app
    nav
        a[href="#home"] Home
    %slot

%view home #public
p Welcome

%view user/{userId} #public
p User {params.userId}
```

In JavaScript:
```javascript
app.def("route file.js,file.css\nuser/{id} user.js")
app.show("home")
app.get(url, params)
app.param(["user"], function(value, name, view, params) { /* resolve */ })
```

### View Lifecycle

Navigation: `app.show(url)` → route match → `ping` (each view, async-friendly with `this.wait()`) → render → `open` → `show`.

| Event | When |
|-------|------|
| `ping` | Before render, fetch data here. Call `this.wait()` for async. |
| `pong` | After render |
| `open` | View becomes active |
| `close` | View deactivated |
| `nav` | Navigation started |
| `show` | Navigation complete |
| `resize` | Viewport resized |

### Scope Variables

| Variable | Contains |
|----------|----------|
| `$s` | Current scope |
| `$el` | Current element |
| `$ui` | View router (in templates; use chosen var name in plain JS) |
| `$d` | Global scope |
| `$up` | Parent scope |
| `$i` | Loop index (inside `;each`) |
| `$len` | Loop length (inside `;each`) |
| `_()` | i18n format function |
| `params` | URL parameters |

## El API

`El(selector)` — Create DOM element from CSS selector string.

```javascript
El("div#id.class1.class2[data-x=1]")  // Create element
```

### Static Methods

| Method | Purpose |
|--------|---------|
| `El.append(parent, child)` | Append, handles slots |
| `El.render(el)` | Process bindings on element tree |
| `El.scope(el, parent)` | Get/create scope for element |
| `El.cls(el, name, add, sel, delay)` | Add/remove/toggle class (optional auto-revert after delay ms) |
| `El.flip(el, sel, fn, opts)` | FLIP animation (snapshot, mutate, animate) |
| `El.get(el, attr)` | Get attribute |
| `El.val(el, val)` | Get/set form value (handles nested forms, selects, checkboxes) |
| `El.kill(el, transition)` | Remove element (with optional CSS transition) |
| `El.empty(el)` | Remove all children |
| `El.replace(old, new)` | Replace element |
| `El.closest(el, sel)` | Find closest ancestor matching selector |
| `El.matches(el, sel)` | Test if element matches selector |
| `El.nearest(el, sel)` | Find
Files: 1
Size: 16.7 KB
Complexity: 20/100
Category: Design

Related in Design