# Coming from Lit
Lit and Zoijs both use **tagged-template HTML with no build step** — the authoring style is very similar. Zoijs adds built-in fine-grained reactivity (signals, computeds) and keyed lists, and isn't tied to Web Components.
## Concept map
| Lit | Zoijs |
|---|---|
| `html\`...\`` | `html\`...\`` (same idea) |
| `@click=${fn}` | `onclick=${fn}` |
| `?disabled=${x}` (boolean) | `disabled=${() => x.get()}` (boolean handled automatically) |
| `.value=${x}` (property) | `value=${() => x.get()}` (`value`/`checked` use the property automatically) |
| reactive properties on a `LitElement` | `createState` / `computed` |
| `repeat(items, keyFn, template)` | `each(() => items.get(), keyFn, template)` |
| render into a custom element | `mount(component, target)` into any element |
## Example
```js
// Lit
class MyCounter extends LitElement {
static properties = { count: { type: Number } };
constructor() { super(); this.count = 0; }
render() {
return html``;
}
}
```
```js
// Zoijs
function Counter() {
const count = createState(0);
return html``;
}
mount(Counter, "#app");
```
## Differences to note
- **No class / Web Component required.** A component is just a function; `mount` renders into any DOM element. (You *can* render into a custom element if you want.)
- **Reactivity is built in.** Instead of `LitElement` reactive properties, use `createState`/`computed`. Changing state updates the DOM automatically.
- **Binding syntax is HTML-native.** Zoijs uses `onclick=` (not `@click=`) and handles boolean/property attributes by name (`disabled`, `value`, `checked`) rather than `?`/`.` prefixes.
- **Reads in templates need `() =>`** to be live: `${() => count.get()}`.
## What's familiar
The "parse a tagged template once, update only the dynamic parts" model is essentially the same as Lit's — so the performance characteristics and the no-build workflow will feel right at home.