{"id":16545588,"url":"https://github.com/maxpert/htmxido","last_synced_at":"2025-05-02T18:31:37.624Z","repository":{"id":213900351,"uuid":"735208758","full_name":"maxpert/htmxido","owner":"maxpert","description":"HTMX generation in Python 3 using DSL","archived":false,"fork":false,"pushed_at":"2024-01-17T15:08:12.000Z","size":36,"stargazers_count":21,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-23T20:04:57.853Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxpert.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2023-12-24T04:02:43.000Z","updated_at":"2024-12-10T16:23:41.000Z","dependencies_parsed_at":"2023-12-24T07:14:17.828Z","dependency_job_id":"d0847087-cab3-4b7d-87e4-ff034cadd078","html_url":"https://github.com/maxpert/htmxido","commit_stats":null,"previous_names":["maxpert/htmxido"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxpert%2Fhtmxido","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxpert%2Fhtmxido/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxpert%2Fhtmxido/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxpert%2Fhtmxido/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxpert","download_url":"https://codeload.github.com/maxpert/htmxido/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252088503,"owners_count":21692806,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-10-11T19:07:04.882Z","updated_at":"2025-05-02T18:31:34.210Z","avatar_url":"https://github.com/maxpert.png","language":"Python","funding_links":[],"categories":["Libraries"],"sub_categories":["General HTML Generation"],"readme":"# What is htmxido?\n\nHTMXido is declerative HTMX generation library for Python.\n\n[![codecov](https://codecov.io/gh/maxpert/htmxido/graph/badge.svg?token=ULBG6B8R39)](https://codecov.io/gh/maxpert/htmxido)\n\n## Install\n\n```\npip install htmxido\n```\n\n## Why?\n\nSince the invention of React SSR (like Next.js), there has been newfound enthusiasm for writing server-side views. Although this method isn't new (consider PHP, the grandfather of all), I was searching for a solution close to writing inline code capable of generating HTML and processing HTMX attributes on those elements.\n\nAfter exploring various libraries and finding them unsatisfactory, I ended up creating something for myself. It later dawned on me that it could benefit more people.\n\n## What does it look like?\n\n```python\nfrom htmxido import domx as x\n\nexample_dom = x.div(id=\"root\", class_=\"bg-white dark:bg-slate-800 rounded-lg px-6 py-8 ring-1 ring-slate-900/5 shadow-xl\")(\n    x.h1(hxIndicator=\"#spinner\")('Hello World'),\n    x.p('You can have nested elements like this:'),\n    x.ul(\n        x.li(f\"Item {i}\") for i in range(1, 3)\n    ),\n    x.div('Not only that but also you can have HTMX attributes'),\n    x.button(hxTarget=\"rubber-band\")('Click me')\n    x.img(id=\"spinner\", src=\"loading.gif\", class_=\"spinner-animation\")\n)\n\nprint(str(example_dom))\n```\n\n**NOTE**: Any keyword attributes should be suffixed with `_`, and they will be removed as per showin in following output.\n\n```html\n\u003cdiv id=\"root\" class=\"bg-white dark:bg-slate-800 rounded-lg px-6 py-8 ring-1 ring-slate-900/5 shadow-xl\"\u003e\n    \u003ch1 hx-indicator=\"#spinner\"\u003eHello World\u003c/h1\u003e\n    \u003cp\u003eYou can have nested elements like this:\u003c/p\u003e\n    \u003cul\u003e\u003cli\u003eItem 1\u003c/li\u003e\u003cli\u003eItem 2\u003c/li\u003e\u003c/ul\u003e\n    \u003cdiv\u003eNot only that but also you can have HTMX attributes\u003c/div\u003e\n    \u003cbutton hx-target=\"rubber-band\"\u003eClick me\u003c/button\u003e\n    \u003cimg id=\"spinner\" src=\"loading.gif\" class=\"spinner-animation\"/\u003e\n\u003c/div\u003e\n```\n\n## So I can write views like code, what's the big deal?\n\nAs much as people hated PHP and made fun of it, with the invention of HTMX, it has become evident that building medium-sized applications in React is bloated (as React was intended for smaller parts of the page). The effort engineers put into basic tasks that could be accomplished by merely sending back HTML from the server was underestimated.\n\nWhile you might be averse to the idea of replacing .innerHTML the old-school way, it turns out you can achieve a lot with just HTMX and jQuery-like declarative DOM ([here is an example](https://www.youtube.com/watch?v=3GObi93tjZI)).\n\nNow, there are a few excellent aspects that backend developers will truly appreciate about htmxido:\n\n - **It's all Python** - This means it runs fast! You can use existing tooling and linters.\n - **Lazy evaluated** - Unless you serialize your DOM (with conversion to str), it remains a DOM! This implies that you can cache for even more speed.\n - **Functional components** - You can easily envision view functions returning these DOM elements that can be reused across requests.\n\nSo in a nutshell you can do something like this:\n\n```python\nfrom htmxido import DOMElement, domx\n\n## Imagine more functional components here\n\n## For this example let's imagine we want to render a header component with hamburger menu.\n@cached(ttl=3600)\ndef header(account: AccountInfo) -\u003e DOMElement:\n    \"\"\"\n    Returns header DOM component for given element account info\n    \"\"\"\n    return domx.div(class_=\"nav-bar full-width responsive\")(\n        domx.h1(f\"Welcome {account.name}\"),\n        hamburger(account) # Reusing another component\n    )\n```\n\n### More usage examples:\n\nHere is an example app Sanic:\n\n```python\nfrom sanic import Sanic, html\nfrom htmxido import domx as x\n\napp = Sanic(\"Pythia\")\n\n@app.post(\"/clicked\")\nasync def clicked(request):\n    return html(str(\n        x.div(\"Clicked!!!\")\n    ))\n\n@app.get(\"/\")\nasync def home(request):\n    return html(str(\n        x.html(\n            x.head(\n                x.script(src=\"https://unpkg.com/htmx.org@1.9.9\")\n            ),\n            x.body(\n                x.h1(\"Running htmxido\"),\n                x.div(id=\"container\")(\n                    x.button(\"Reveal!!!\", hxTarget=\"#container\", hxTrigger=\"click\", hxPost=\"/clicked\")\n                ),\n            )\n        )\n    ))\n```\n\n## Contributing\n\nI use pytest for testing, and coverage for coverage report. You can simply run tests by:\n\n```sh\ncoverage run -m pytest \u0026\u0026 coverage html \u0026\u0026 open htmlcov/index.html\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxpert%2Fhtmxido","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxpert%2Fhtmxido","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxpert%2Fhtmxido/lists"}