{"id":28959465,"url":"https://github.com/onehundredthousand/jtml","last_synced_at":"2026-04-18T05:03:03.725Z","repository":{"id":300394721,"uuid":"1006033570","full_name":"OneHundredThousand/jtml","owner":"OneHundredThousand","description":"HTML-first JSON templating, inspired by HTMX.","archived":false,"fork":false,"pushed_at":"2026-03-29T17:04:12.000Z","size":242,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-29T19:26:43.104Z","etag":null,"topics":["html","js","json","template-first"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OneHundredThousand.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-21T10:42:39.000Z","updated_at":"2026-03-29T17:04:16.000Z","dependencies_parsed_at":"2025-06-21T13:26:40.794Z","dependency_job_id":"56f7f29c-9b98-4034-a5b7-c43d7880c8f9","html_url":"https://github.com/OneHundredThousand/jtml","commit_stats":null,"previous_names":["onehundredthousand/jtml"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/OneHundredThousand/jtml","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OneHundredThousand%2Fjtml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OneHundredThousand%2Fjtml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OneHundredThousand%2Fjtml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OneHundredThousand%2Fjtml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OneHundredThousand","download_url":"https://codeload.github.com/OneHundredThousand/jtml/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OneHundredThousand%2Fjtml/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31957158,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T00:39:45.007Z","status":"online","status_checked_at":"2026-04-18T02:00:07.018Z","response_time":103,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["html","js","json","template-first"],"created_at":"2025-06-24T00:01:50.736Z","updated_at":"2026-04-18T05:03:03.720Z","avatar_url":"https://github.com/OneHundredThousand.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JTML\n\nJTML is a lightweight, attribute-driven JavaScript micro-library that turns plain HTML into interactive, data-driven UI — without becoming a framework.\n\n- No virtual DOM  \n- No components  \n- No build step required  \n- No hidden lifecycle  \n\n**JTML = JSON Template Markup Language**\n\n---\n\n## ✨ Core Ideas\n\n- HTML defines structure and behavior  \n- One actor element = one action  \n- Templates stay in `\u003ctemplate\u003e`  \n- JSON is the default data shape  \n- Explicit over implicit  \n\nJTML enhances real HTML — it doesn’t replace it.\n\n---\n\n## 🚀 Quick Start\n\n```html\n\u003cform \n  action=\"/posts\"\n  method=\"GET\"\n  jt-render=\"#posts-template\"\n  jt-target=\"#output\"\n  jt-load\n\u003e\n\u003c/form\u003e\n\n\u003ctemplate id=\"posts-template\"\u003e\n  \u003cul\u003e\n    \u003cli jt-foreach=\"items\"\u003e\n      \u003cspan jt-text=\"{title}\"\u003e\u003c/span\u003e\n    \u003c/li\u003e\n  \u003c/ul\u003e\n\u003c/template\u003e\n\n\u003cdiv id=\"output\"\u003e\u003c/div\u003e\n\n\u003cscript src=\"jtml.js\"\u003e\u003c/script\u003e\n```\n\nIf `/posts` returns JSON like:\n\n```json\n{\n  \"items\": [\n    { \"title\": \"First\" },\n    { \"title\": \"Second\" }\n  ]\n}\n```\n\nJTML renders it automatically.\n\n---\n\n## ⚡ Supported Events\n\nJTML binds behavior using `jt-*` attributes.\n\n- `jt-click`\n- `jt-submit`\n- `jt-input`\n- `jt-change`\n- `jt-load`\n\nExample:\n\n```html\n\u003cbutton \n  jt-click=\"handleClick\"\n  jt-render=\"#result\"\n  jt-target=\"#out\"\u003e\n  Click\n\u003c/button\u003e\n```\n\n```javascript\nfunction handleClick(el, event) {\n  console.log(\"clicked\");\n}\n```\n\nIf the handler returns `false`, rendering is skipped.  \nIf it returns a `Promise`, rendering waits.\n\n---\n\n## 🔁 Forms \u0026 Anchors (Requests)\n\nForms and anchors automatically use `fetch()`.\n\n```html\n\u003cform\n  action=\"/users\"\n  method=\"POST\"\n  jt-render=\"#user-template\"\n  jt-target=\"#users\"\n  jt-store=\"usersData\"\n\u003e\n\u003c/form\u003e\n```\n\n### Behavior\n\n- `GET` → query string via `URLSearchParams`\n- `POST`, `PUT`, `PATCH` → JSON body\n\nResponse auto-parsed:\n\n- `application/json` → `res.json()`\n- `text/html` → `res.text()`\n\n---\n\n## 🧩 Rendering (`jt-render`)\n\n`jt-render` points to a `\u003ctemplate\u003e`.\n\n```html\n\u003ctemplate id=\"user-template\"\u003e\n  \u003cdiv\u003e\n    \u003ch3 jt-text=\"{name}\"\u003e\u003c/h3\u003e\n    \u003cp jt-text=\"{email}\"\u003e\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n### Supported Template Directives\n\n- `jt-text=\"{path.to.value}\"`\n- `jt-foreach=\"items\"`\n- `jt-if=\"count gt 0\"`\n- `jt-attr:href=\"{url}\"`\n\n### Conditional Operators\n\n- `eq`\n- `neq`\n- `gt`\n- `lt`\n- `gte`\n- `lte`\n\nExample:\n\n```html\n\u003cdiv jt-if=\"count gt 0\"\u003e\n  Has items\n\u003c/div\u003e\n```\n\nTemplates are compiled once and cached automatically.\n\n---\n\n## 🎯 Targets (`jt-target`)\n\n```html\njt-target=\"#output\"\n```\n\nIf omitted, rendering happens in place.\n\n---\n\n## 🔄 Swap Strategies (`jt-swap`)\n\nControls how output is inserted:\n\n| Value   | Behavior                     |\n|---------|-----------------------------|\n| replace | Replace children (default)  |\n| append  | Append output               |\n| prepend | Prepend output              |\n\nExample:\n\n```html\n\u003cform jt-swap=\"append\"\u003e...\u003c/form\u003e\n```\n\n---\n\n## 🧠 Global Store\n\nJTML includes a tiny key/value store.\n\n```javascript\nJTML.store.add(\"user\", { name: \"Arthur\" });\n\nconst user = JTML.store.get(\"user\");\n```\n\nUse it via `jt-source`:\n\n```html\n\u003cdiv \n  jt-source=\"user\"\n  jt-render=\"#profile-template\"\u003e\n\u003c/div\u003e\n```\n\nThe stored object becomes the render context.\n\n---\n\n## ⏳ Loading \u0026 Error States\n\n```html\n\u003cform\n  jt-loading=\"#loading\"\n  jt-error=\"#error\"\u003e\n\u003c/form\u003e\n```\n\n- `jt-loading` → shown during request  \n- `jt-error` → shown if request fails  \n\n---\n\n## 🪝 Lifecycle Hooks\n\nHooks are plain global functions.\n\n```html\n\u003cform\n  jt-pre-request-fn=\"beforeReq\"\n  jt-post-request-fn=\"afterReq\"\n  jt-request-error-fn=\"onError\"\u003e\n\u003c/form\u003e\n```\n\n```javascript\nfunction beforeReq(el, options) {}\nfunction afterReq(el, response, body) {}\nfunction onError(el, error) {}\n```\n\nNo framework lifecycle. Just functions.\n\n---\n\n## 🔍 Debug Mode\n\nEnable via query string:\n\n```html\n\u003cscript src=\"jtml.js?debug\"\u003e\u003c/script\u003e\n```\n\nOptional flags:\n\n- `?debug`\n- `?debug\u0026debug-only`\n- `?debug\u0026debug-verbose`\n\nLogs actor processing details to the console.\n\n---\n\n## 🔄 Manual Re-Apply\n\nJTML runs automatically on `DOMContentLoaded`.\n\nYou can manually re-bind:\n\n```javascript\nJTML.apply();\n```\n\nOr apply to a subtree:\n\n```javascript\nJTML.apply(someElement);\n```\n\n---\n\n## 🧠 Philosophy\n\nJTML is intentionally not a framework.\n\n- No component system  \n- No router  \n- No global state management  \n- No hidden diffing  \n- No magical reactivity  \n\nIt enhances HTML with predictable, explicit behavior.\n\nIf things get complicated, use plain JavaScript.  \nJTML doesn’t try to compete with full frameworks — it avoids becoming one.\n\n---\n\n## 📄 License\n\nMIT","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonehundredthousand%2Fjtml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonehundredthousand%2Fjtml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonehundredthousand%2Fjtml/lists"}