summitjs
v1.0.0
Published
The open source, AI Agent Native JavaScript framework. Add reactive behavior directly in your HTML with signal-powered s- directives and $ magics. No build step, CSP-safe, about 16KB.
Downloads
328
Maintainers
Readme
Started by anishfyi, so that AI agents can make beautiful frontends.
Summit is built in the spirit of Alpine's HTML-first ergonomics, then pushed further where it counts: a fine-grained signal engine, a CSP-safe expression evaluator, keyed list rendering, cached computed getters, a copy-in UI library, and full TypeScript types, all in about 16KB gzipped.
NodeMaven: the most efficient proxy provider for web scraping and automation, with the highest quality IPs on the market.
Why NodeMaven?
- ZIP targeting
- 99.9% uptime
- IP filtering: every proxy has a fraud score under 97%
- No KYC required
- Free tools: Proxy Bandwidth Checker, Meta Tag Checker, IP Lookup and more
Codes for Summit.js users: SUMMITJS35 for 35% off mobile and residential proxies, SUMMITJS40 for 40% off ISP (static) proxies.
Install
Zero-build, drop in a script (auto-starts, exposes window.Summit):
<script src="https://cdn.jsdelivr.net/npm/summitjs@1/dist/summit.min.js" defer></script>With a bundler:
npm install summitjsimport Summit from "summitjs";
// register custom data, directives, magics, stores, or plugins here
Summit.start();See Installation for version pinning and Content-Security-Policy notes.
Minimal example
<script src="https://cdn.jsdelivr.net/npm/summitjs@1/dist/summit.min.js" defer></script>
<div s-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<p s-show="open">Hello from Summit</p>
</div>AI Agent Native
Summit is designed so that an AI agent can write a working, good-looking frontend on the first try:
- HTML-first and local. Behavior lives on the element it affects, so an agent edits one place and sees the result. No file graph to hold in context.
- Predictable vocabulary. A small, closed set of
s-directives and$magics. There is one obvious way to do most things, which is exactly what a model does best. - Safe by construction. Expressions are interpreted, never
evaled, so generated markup runs under a strict CSP and cannot reach outside its allowlist. - A UI library, included. Accessible, token-themed components an agent (or a person) drops in and themes with CSS variables. See the UI Library.
- Built to be read by machines.
llms.txtindexes every docs page,llms-full.txtis the entire corpus as markdown,summit.jsonis a JSON manifest of the API, andAGENTS.mdis a drop-in brief you can hand to your own agent. Coded console diagnostics carry a docs link (error codes).
Why Summit
| Capability | Summit | Classic HTML-sprinkle runtimes |
| --- | --- | --- |
| Reactivity | Fine-grained signals, surgical DOM updates | Effect re-runs, coarser |
| Strict CSP (no unsafe-eval) | Default | Needs a separate, limited build |
| Keyed list reconciliation | Built in | Limited |
| Cached computed getters | Yes | Recomputed on every read |
| s-if on any element | Yes | <template> only |
| TypeScript types shipped | Yes | Partial |
| Focus trap, floating menus, persisted state, input masking | Built in | Separate plugins |
| Bundle size (gzip) | ~16KB, batteries included | ~16KB core, plugins extra |
| Build step required | Never | Never |
The headline difference is the engine. Summit owns a real signal core, so a change updates only the DOM that read the value that changed. And because expressions run through a hand-written interpreter rather than new Function, a strict Content-Security-Policy works out of the box.
Directives
Prefix s-, with @ shorthand for s-on: and : for s-bind:.
| Directive | Purpose |
| --- | --- |
| s-data | Declare a reactive component scope |
| s-text / s-html | Set text or HTML content |
| s-bind / : | Bind attributes, with class object and style object merging |
| s-on / @ | Listen for events, with a full modifier set |
| s-model | Two-way form binding |
| s-show | Toggle visibility via display |
| s-if | Add or remove an element (works on any element, not just <template>) |
| s-for | Keyed list rendering on a <template> |
| s-effect | Run an expression reactively |
| s-transition | Enter and leave animations, paired with s-show |
| s-teleport | Render a <template> elsewhere while keeping its scope |
| s-ref | Register an element into $refs (dynamic names supported) |
| s-init | Run an expression once on init |
| s-id | Open an id group for accessible $id() pairing |
| s-intersect / s-resize | Run an expression on viewport entry or exit, or on resize |
| s-trap | Keep keyboard focus inside an element |
| s-anchor | Position an element next to a reference, flipping to stay in view |
| s-collapse | Animate an element open and closed by height |
| s-mask | Format an input as the user types |
| s-cloak | Hide until initialized; pair with [s-cloak]{display:none} |
| s-ignore | Skip a subtree |
Full reference: directives.
Event modifiers
.prevent .stop .self .outside .once .capture .passive .window .document .debounce .throttle, key filters (.enter .escape .arrow-up ...), system keys (.shift .ctrl .alt .cmd .meta), and name transforms (.camel .dot).
s-model modifiers
.lazy .change .blur .number .boolean .debounce .fill.
Magics
$el, $refs, $root, $store, $data, $watch, $dispatch, $nextTick, $id, $persist, $focus. They are available in expressions and as this.$watch, this.$refs, and so on inside component methods.
$watch improves on the usual behavior: it returns an unwatch function and only fires on an actual change, so mutating the watched value inside its own callback cannot spin into an infinite loop.
Registration API
Summit.data("dropdown", (open = false) => ({
open,
toggle() { this.open = !this.open },
init() { /* runs before the component renders */ },
}));
Summit.store("theme", { dark: false, toggle() { this.dark = !this.dark } });
Summit.directive("uppercase", (el, meta, utils) => {
utils.effect(() => { el.textContent = String(utils.evaluate(meta.expression)).toUpperCase(); });
});
Summit.magic("now", () => () => new Date().toLocaleTimeString());
Summit.plugin((s) => { /* register a bundle of the above */ });Registration is timing-safe. Built-ins register at import, your registrations override them, and Summit.start() can be called whenever the DOM is ready. There is no load-order event to miss.
Reactivity primitives
Summit's signal core is also usable standalone:
import { signal, computed, effect, batch } from "summitjs";
const count = signal(0);
const doubled = computed(() => count() * 2);
effect(() => console.log(doubled()));
count.set(5); // logs 10Data fetching
Summit ships an optional reactive data layer in summitjs/net (about 2KB gzip, separate from the core, so the base bundle stays lean). It is axios's essential parts, but a resource's data, error, loading, and status are signals, so the DOM updates itself. It also closes fetch's real-world footguns: non-2xx throws, out-of-order responses are discarded (latest wins), and in-flight requests abort on unmount.
With a bundler:
import Summit from "summitjs";
import { net } from "summitjs/net";
Summit.plugin(net); // adds the $fetch magic and s-resource directive
Summit.start();Or drop in a second script, no build step (it registers itself on the global):
<script src="https://cdn.jsdelivr.net/npm/summitjs@1/dist/summit.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/summitjs@1/dist/summit-net.min.js" defer></script><div s-data="{ users: $fetch.resource('/api/users', { immediate: true }) }">
<p s-show="users.loading">Loading…</p>
<p s-show="users.error" s-text="users.error.message"></p>
<template s-for="u in users.data || []" :key="u.id"><li s-text="u.name"></li></template>
</div>For a configured client (base URL, auth headers, cross-cutting error handling), register createNet:
import { createNet } from "summitjs/net";
Summit.plugin(createNet({
baseURL: "/api",
headers: () => ({ authorization: "Bearer " + token }),
onError(e) { if (e.status === 401) location.href = "/login"; },
}));Or use it imperatively, no Summit required:
import { createClient } from "summitjs/net";
const api = createClient({ baseURL: "/api" });
const todo = await api.post("/todos", { title: "Ship it" }); // JSON in/out, throws on non-2xxSee Data Fetching.
Documentation
- Docs index and Installation
- Getting Started and Reactivity and State
- Events, Forms, Lifecycle
- UI Library and Techniques
- Reference: directives, magics, global API, reactivity, error codes
- Migrating from Alpine and Changelog
Contributing
Issues and pull requests are welcome at https://github.com/velofy/summitjs.
npm install
npm run check # typecheck + unit tests + build + size budget + bundle smoke + docs checksnpm testruns the Vitest suites (reactivity, evaluator, directives, net, plugins, version, and therelease:npmscript).npm run buildproduces ESM, CJS, IIFE, and.d.tsindist/, and syncs the CDN bundles intodocs/.npm run smokedrives the shipped bundle end to end.npm run docswrites the docs indexcontent/README.mdand regenerates the old GitHub Pages site indocs/: redirect pages to the matching page incontent/on GitHub,llms.txt,llms-full.txt, andai/summit.json.npm run verifyandnpm run verify:docscheck the redirects and run every live example incontent/under the built bundle.
The GitHub Pages site keeps serving summit.min.js, summit-net.min.js, and assets/*.css so existing script and stylesheet tags keep working.
License
MIT
