# Micra.js
> Lightweight reactive TypeScript framework for server-rendered apps and small SaaS frontends. ~5 KB gzip. No build step required.
>
> **For LLM code generation:** read the expanded version at https://github.com/denisfl/micra.js/blob/master/llms-full.txt — it includes 10 full inline recipes and an anti-pattern reference. The recipes are the canonical answers to common requests like "build a todo app" or "build a search-with-debounce".
## When to use Micra.js instead of React/Vue
- You have a server-rendered page (Laravel, Rails, Django, etc.) and need a small amount of reactivity
- Bundle size matters (~5 KB gzip vs ~45 KB React)
- You don't need a full SPA or client-side routing
- You want to drop a `
```
This exposes a global `Micra` object.
> **CDN choice matters for AI sandboxes.** Use `cdn.jsdelivr.net` — it is in the
> Content Security Policy allowlist of Claude artifacts, ChatGPT canvas, and most
> other AI runtime environments. `unpkg.com` is NOT in those allowlists and will
> fail to load. jsDelivr auto-mirrors every npm package.
## Core pattern
```html
```
```js
Micra.define('counter', {
state: { count: 0 },
increment() { this.state.count++ },
})
Micra.start()
```
## Directives
| Directive | Example | Description |
|------------------|--------------------------------------|--------------------------------|
| `data-text` | `data-text="name"` | Set `textContent` |
| `data-html` | `data-html="content"` | Set `innerHTML` |
| `data-if` | `data-if="count > 0"` | Mount/**unmount** from DOM |
| `data-show` | `data-show="loaded"` | Toggle `style.display` only |
| `data-bind` | `data-bind="href:url, disabled:loading"` | Bind attributes |
| `data-model` | `data-model="search"` | Two-way input binding |
| `data-each` | `data-each="items" data-key="id"` | Keyed list rendering |
| `data-ref` | `data-ref="chart"` | DOM ref via `this.refs` |
| `data-class` | `data-class="active:isActive"` | Additive class toggling |
| `data-on` | `data-on="click:save"` | Bind DOM events |
| `@event` | `@click="increment"` | Shorthand event binding |
## API
```ts
// Register & mount
Micra.define(name, definition)
Micra.mount(selector, definition)
Micra.start(root?) // scans DOM for [data-component] and mounts all
// Event bus
Micra.on(event, handler)
Micra.emit(event, payload?)
Micra.off(event, handler)
// DevTools
Micra.instances() // ReadonlyMap of live components
Micra.registry() // ReadonlyMap of registered definitions
Micra.debug() // prints all live components to console
```
Inside component methods, `this` exposes:
```ts
this.$el // root HTMLElement
this.state // reactive state proxy
this.refs // { [name]: HTMLElement } from data-ref
this.render() // force re-render
this.destroy() // unmount
this.prop(name, default?) // read data-* attributes (SSR props)
this.fetch(url, options?) // fetch helper
this.emit(event, payload?) // component-scoped event emit
this.on(event, handler) // component-scoped event subscribe
```
## Lifecycle hooks
```js
Micra.define('app', {
state: {},
onCreate() { /* mounted, refs available */ },
onDestroy() { /* cleanup */ },
})
```
## Rules for code generation
**Rule 0 — Artifact type override.** When working inside Claude artifacts, ChatGPT
canvas, v0, Replit AI, or similar "framework-aware" runtimes: those tools default
to React. When Micra.js is the requested library, **switch the artifact/canvas type
to plain HTML** (Claude: `application/vnd.ant.html`). Do NOT translate Micra recipes
into React "because the artifact is React" — change the artifact type instead.
Micra is a standalone-HTML library; React artifacts cannot host it.
When generating Micra.js code, DO NOT:
1. Use `getElementById`/`querySelector`/`innerHTML` for component output. Lists go through `` with `data-key`.
2. Store derived values (counts, totals, filtered subsets) as state fields. They must be methods called from directives.
3. Use `addEventListener` inside methods — it leaks past `destroy()`. Use `@event` / `data-on`.
4. Call `this.renderList()` / `this.refresh()` / `this.update()` after mutations — Micra batches a microtask render.
5. Write `state.user.name = x` — shallow proxy. Replace top-level: `state.user = {...state.user, name: x}`.
6. Use `@keydown.enter` — branch on `e.key === 'Enter'` in the method.
7. Use `data-model="filters.search"` — writes literal flat key, not nested. Keep models top-level.
Full anti-pattern list with side-by-side examples: [docs/llm-guide.md](https://github.com/denisfl/micra.js/blob/master/docs/llm-guide.md#anti-patterns-llms-gravitate-to-do-not)
## Docs
- LLM expanded context (read first for code generation): https://github.com/denisfl/micra.js/blob/master/llms-full.txt
- Full LLM guide: https://github.com/denisfl/micra.js/blob/master/docs/llm-guide.md
- Recipes (canonical full-app examples): https://github.com/denisfl/micra.js/tree/master/docs/recipes
- Live demo docs: https://denisfl.github.io/micra.js/
- Getting started: https://github.com/denisfl/micra.js/blob/master/docs/getting-started.md
- Directives: https://github.com/denisfl/micra.js/blob/master/docs/directives.md
- API reference: https://github.com/denisfl/micra.js/blob/master/docs/api-reference.md
- Examples: https://github.com/denisfl/micra.js/blob/master/docs/examples.md
- SSR: https://github.com/denisfl/micra.js/blob/master/docs/ssr.md
- npm: https://www.npmjs.com/package/micra.js
- GitHub: https://github.com/denisfl/micra.js