# No.JS
> No.JS is an HTML-first reactive framework for building dynamic web applications using only HTML attributes. Zero dependencies, no build step, no virtual DOM, CSP-compliant. Include one script tag and start writing directives.
No.JS replaces JavaScript framework boilerplate with declarative HTML attributes. Directives like `get`, `bind`, `state`, `foreach`, `if`, and `on:click` handle data fetching, rendering, state management, and interactivity — all without writing JavaScript. Data lives in reactive contexts (Proxy-backed) that inherit through the DOM like lexical scoping. Directives execute by priority: state (0) → HTTP/error-boundary (1) → computed/watch (2) → ref (5) → structural (10) → rendering/events (20) → validation (30).
## Getting Started
- [Installation & Quick Start](https://no-js.dev/#/getting-started): CDN script tag, minimal example, how the framework initializes and processes the DOM
## Core Guides
- [Data Fetching](https://no-js.dev/#/data-fetching): Declarative HTTP via `get`, `post`, `put`, `patch`, `delete`, `query` (QUERY, RFC 10008) attributes; base URL, caching, polling, reactive URLs, loading/error/empty templates
- [Server-Sent Events](https://no-js.dev/#/sse): `sse` directive for streaming data via EventSource; insert modes (replace, append, prepend), named events, `$sse` connection state, reactive URLs, store integration, error templates, per-message `then` callback
- [Data Binding](https://no-js.dev/#/data-binding): `bind` (text), `bind-html` (sanitized HTML), `bind-*` (any attribute), `model` (two-way input binding)
- [State Management](https://no-js.dev/#/state-management): `state` (local reactive data), `store` (global named stores), `computed` (derived values), `watch` (reactive side effects), `into` (write to store), persistence via `persist`/`persist-fields`
- [Conditionals](https://no-js.dev/#/conditionals): `if`/`else-if`/`else` with `then` templates, `show`/`hide` (CSS toggle), `switch`/`case`
- [Loops](https://no-js.dev/#/loops): `foreach` (primary iteration directive), `each` and `for` (aliases), `foreach="item in array"` syntax, inline children or external template, filter, sort, limit, offset, loop variables (`$index`, `$count`, `$first`, `$last`, `$even`, `$odd`), keyed updates, nesting
- [Templates](https://no-js.dev/#/templates): `` fragments, `use` for reuse, named `` elements, remote templates via `src`, preloading
## Interaction
- [Events](https://no-js.dev/#/events): `on:click`, `on:keydown.enter`, `on:submit.prevent`; modifiers (`.stop`, `.once`, `.debounce.300`); lifecycle hooks (`on:mounted`, `on:init`, `on:updated`, `on:error`, `on:unmounted`); `$event` and `$el` references
- [Forms & Validation](https://no-js.dev/#/forms-validation): `validate` attribute with built-in rules (`required`, `email`, `min`, `max`, `pattern`); `$form` context for form state; custom validators via `NoJS.validator()` (requires `@no-js-dev/nojs-elements` plugin since v1.13.0)
- [Actions & Refs](https://no-js.dev/#/actions-refs): `call` (trigger HTTP from any element), `trigger` (dispatch custom events), `ref` (name an element), `$refs` (access named elements)
## Presentation
- [Dynamic Styling](https://no-js.dev/#/styling): `class-active="isActive"`, `class-map="{ dark: isDark }"`, `style-color="themeColor"`, `style-map="{ opacity: fade }"`
- [Animations](https://no-js.dev/#/animations): `animate` attribute with built-in keyframes (fadeIn, fadeInUp, slideInLeft, bounceIn, zoomIn, etc.), `transition` for enter/leave, stagger for lists
- [Filters & Pipes](https://no-js.dev/#/filters): 32 built-in filters via pipe syntax (`value | uppercase | truncate:20`); text, number, array, date, and utility filters; custom filters via `NoJS.filter()`
## Advanced
- [Routing](https://no-js.dev/#/routing): SPA navigation with `route="/path/:param"`, `route-view` outlet, route guards, nested routes, View Transition API (slide, fade, scale presets), file-based routing, query params, hash navigation, redirects, 404 handling
- [Head Management](https://no-js.dev/#/head-management): Per-route `page-title`, `page-description`, `page-canonical`, `page-jsonld` attributes on ``
- [Internationalization](https://no-js.dev/#/i18n): `t="key"` directive, pluralization, locale switching, async locale loading, fallback chains, interpolation
- [Drag and Drop](https://no-js.dev/#/drag-and-drop): `drag` source, `drop` zone, `drag-list` for sortable reordering, multi-select, custom placeholders, event handlers (requires `@no-js-dev/nojs-elements` plugin since v1.13.0)
- [Custom Directives](https://no-js.dev/#/custom-directives): Extend the framework via `NoJS.directive(name, { priority, init(el, name, value) })` with full access to the reactive context
- [Error Handling](https://no-js.dev/#/error-handling): Per-element `error` templates, `error-boundary` for subtree isolation, global error handler via `NoJS.on('error', fn)`
- [Configuration](https://no-js.dev/#/configuration): `NoJS.config()` for global settings (baseApiUrl, headers, timeout, retries), request/response interceptors, CSRF token support
## Public API
Methods and properties on the `NoJS` object (`window.NoJS` via CDN):
### Configuration
- `NoJS.config(opts?: object): void` — Merge global settings. Keys: `baseApiUrl` (string), `headers` (object), `timeout` (number, ms), `retries` (number), `cache` (object), `templates` (object), `router` (object), `i18n` (object), `stores` (object), `exprCacheSize` (number, default 500), `dangerouslyDisableSanitize` (boolean), `maxEventListeners` (number), `debug` (boolean), `appId` (string), `csrf` (object). Security-critical keys (`sanitize`, `dangerouslyDisableSanitize`, `sanitizeHtml`) are locked after `init()`.
- `NoJS.baseApiUrl: string` — Get or set the base API URL for fetch directives.
### Lifecycle
- `NoJS.init(root?: HTMLElement): Promise` — Initialize the framework. Loads i18n locales, processes template includes, loads remote templates (phase 1 blocking, phase 2 background), activates the router if a `[route-view]` element exists, processes the DOM tree, and runs plugin `init` hooks. Called automatically by the CDN build; manual for ESM/CJS. Returns a Promise that resolves when first paint is complete.
- `NoJS.dispose(): Promise` — Full teardown. Awaits any in-flight `init()`, disposes plugins in reverse installation order (with 3s timeout each), clears globals, interceptors, router, and devtools. Resets config lock.
### Plugin System
- `NoJS.use(plugin: object | function, options?: object): void` — Register a plugin. Plugin must have `{ name: string, install: function }` or be a named function. The `install(NoJS, options)` callback runs immediately. If `init()` has already completed and the plugin has an `init` method, it is called. Options: `{ trusted: true }` grants access to sensitive HTTP headers.
- `NoJS.global(name: string, value: any): void` — Register a reactive global accessible as `$name` in expressions. Validates identifier format, blocks reserved names and prototype pollution vectors, sanitizes object values, and wraps in a reactive context. Notifies all store watchers on registration.
- `NoJS.internals: object` — Frozen object exposing semi-private APIs for trusted plugins: `execStatement`, `cloneTemplate`, `disposeChildren`, `disposeTree`, `warn`, `validators`, `removeCoreDirective`, `onDispose`.
### Directives, Filters, and Validators
- `NoJS.directive(name: string, handler: object): void` — Register a custom directive. Handler: `{ priority: number, init(el: HTMLElement, attrName: string, value: string): void }`. Core directives are frozen after `init()` — plugins can add new ones but not override built-ins.
- `NoJS.filter(name: string, fn: function): void` — Register a custom filter for pipe syntax (`value | filterName`). Built-in filter names cannot be overridden. Throws `TypeError` if name or fn is invalid.
- `NoJS.validator(name: string, fn: function): void` — Register a custom form validation rule. Built-in validator names (`required`, `email`, `url`, `min`, `max`, `minlength`, `maxlength`, `pattern`, `match`, `number`, `integer`, `alpha`, `alphanumeric`) cannot be overridden. Throws `TypeError` if name or fn is invalid.
### Internationalization
- `NoJS.i18n(opts: object): void` — Configure i18n. Options: `loadPath` (string, e.g. `/locales/{locale}.json`), `defaultLocale` (string), `fallbackLocale` (string), `persist` (boolean, saves to localStorage), `detectBrowser` (boolean), `supportedLocales` (array of locale codes; required to enable `detectBrowser` under `loadPath` since no bundles are loaded when detection runs — first-visit priority: persisted `nojs-locale` > browser detection > `defaultLocale`), `ns` (array of namespace strings), `cache` (boolean), `locales` (object mapping locale codes to metadata).
- `NoJS.locale: string` — Get or set the active locale. Setting triggers re-fetch of all loaded namespaces for the new locale.
### Event Bus
- `NoJS.on(event: string, fn: function): function` — Subscribe to a global event. Returns an unsubscribe function. Warns on listener count exceeding `maxEventListeners` (configurable, helps detect memory leaks).
### HTTP Interceptors
- `NoJS.interceptor(type: 'request' | 'response', fn: function): void` — Register a request or response interceptor. Supports async functions. When called inside a plugin's `install()`, the interceptor is tracked to that plugin. Request interceptors can return `NoJS.CANCEL` (abort), `NoJS.RESPOND` (short-circuit with mock), or `NoJS.REPLACE` (swap response data).
### State
- `NoJS.store: object` — Access the global store object. Stores are created via `NoJS.config({ stores: { name: data } })` or the `store` directive.
- `NoJS.notify(): void` — Trigger UI update after external JavaScript mutations to store data. Notifies all store watchers.
### Routing
- `NoJS.router: object | null` — Access the router instance (created when a `[route-view]` element exists). Methods: `push(path)`, `replace(path)`, `back()`, `forward()`. `null` if no route-view outlet is in the DOM.
### Sentinel Symbols
- `NoJS.CANCEL: Symbol` — Return from a request interceptor to abort the request.
- `NoJS.RESPOND: Symbol` — Return from a request interceptor to short-circuit with a mock response.
- `NoJS.REPLACE: Symbol` — Return from a response interceptor to replace the response data.
### Utility Functions (for custom directives)
- `NoJS.createContext(data: object): Proxy` — Create a new reactive context (Proxy-backed) from a plain object.
- `NoJS.evaluate(expr: string, context: object): any` — Evaluate a No.JS expression against a reactive context. CSP-safe, no eval.
- `NoJS.resolve(expr: string, context: object): any` — Resolve a dotted property path against a context.
- `NoJS.findContext(el: HTMLElement): object | null` — Walk up the DOM to find the nearest reactive context attached to an ancestor element.
- `NoJS.processTree(root: HTMLElement): void` — Walk a DOM subtree and execute all matching directives by priority.
### Metadata
- `NoJS.version: string` — The framework version string (e.g. `"1.17.0"`).
- Latest release: **v1.17.0** — adds the `query` directive (HTTP QUERY, RFC 10008): a safe, idempotent, cacheable read that carries a request body, with body-aware caching and `query-trigger*` companions (see the [Changelog](https://github.com/no-js-dev/nojs/blob/main/CHANGELOG.md)).
## Reference
- [Directive Compatibility](https://no-js.dev/#/directive-compatibility): Same-element directive interactions, known limitations with workarounds, v1.18.0 migration notes (`if` gates the element, `use` priority 9, per-clone computed/watch)
- [Directive Cheatsheet](https://no-js.dev/#/cheatsheet): Every directive with syntax, attributes, and usage at a glance
- [Examples](https://no-js.dev/#/examples): Full SPA example with routing, authentication, i18n, and CRUD
- [Playground](https://no-js.dev/#/playground): Interactive multi-file code editor with live preview
- [Full Documentation](https://no-js.dev/llms-full.txt): Complete documentation content in a single file for deep context
## Ecosystem
- [NoJS Elements](https://elements.no-js.dev): UI element plugins — drag-and-drop, form validation, tooltips, popovers, modals, dropdowns, toasts, tabs, trees, steppers, skeletons, split panes, sortable tables
- [NoJS LSP](https://lsp.no-js.dev): VS Code language server extension — completions for 45+ directives, real-time diagnostics, hover docs, go-to-definition, semantic highlighting, code actions, and 41 built-in snippets
- [NoJS Skill](https://github.com/no-js-dev/nojs-skill): Claude Code AI skill for No.JS development
- [GitHub](https://github.com/no-js-dev/nojs): Source code, issues, and contributions
- [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=exs.nojs-lsp): Install the NoJS LSP extension directly