Repository navigation
HaTchi-MaXchi — an htmx-native design system (Hyperparts, not “components”) #3936
manwithacat
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Hi all,
I wanted to share a project that’s been cooking in the open and is aimed squarely at people building real apps with htmx (and at the coding agents that increasingly author that markup).
HaTchi-MaXchi is an htmx-native design system: server-rendered partials, semantic classes + design tokens, and a small amount of vanilla JS only where the platform doesn’t give you a primitive. The goal is the maturity of a modern component aesthetic (complete interaction states, dark as a material, disciplined spacing) without a client framework, SPA state graph, or “rebuild the world in JS.”
Live gallery (demo markup is the copy-paste snippet, so the two cannot drift):
https://manwithacat.github.io/hatchi-maxchi/
Why not just call them components?
Because “component” drags in the wrong priors.
In React-land a component bundles structure, behaviour, and client state into a tree. Agents (and a lot of human muscle memory) hear “component” and reach for props, local state, composition via imports, and JSON APIs.
That’s a poor fit for hypermedia. On the htmx path, the durable unit is closer to:
A Hyperpart has no client state graph. Application state lives on the server; the DOM is the client’s working memory; htmx swaps markup. Controllers are document-delegated IIFEs — not a mini-React, not Alpine-as-framework-in-the-design-system.
The naming is deliberate. If you tell a model (or a junior engineer) to “build a component,” you get React-shaped answers. If you tell them to implement a Hyperpart, the job description is: this markup → this DOM contract → this exchange.
Vocabulary here follows Hypermedia Systems: the round-trip is a hypermedia exchange; the control that starts it is an affordance. We just made that first-class in the design system, not a footnote.
The half of the problem “component libraries” often skip
Most design systems that grow up around SPAs can get away without standardising what the server owes the browser. React resolves state locally; the “API” is often props and events.
Interactive Hyperparts can’t. If a button says
hx-get="/…"and the server returns the wrong shape, the UI is broken even if the CSS is perfect. So the gallery documents, for interactive parts:That’s the piece we treat as design-system surface, not app-private folklore.
Internally we call the freeze between design system and host a dual-lock (DOM contract ± schema): roughly “if Zod is for JSON, this is for the fragment.” It’s aimed at multi-host honesty and CI, not at making the gallery heavier to use. Standalone htmx apps can ignore the dual-lock machinery entirely and still copy markup + implement the exchange.
Design philosophy (short)
A few stances that show up everywhere:
data-*variants carry variation — not a second styling language of utility soup./mock/*, flash “Deleted (demo).” toasts) are scaffolding. Production implements the exchange row, not the mock host.If that sounds like “just write good HTML,” good — the kit’s job is to make good the default, and checkable when agents or teams scale.
AI-first tooling (on purpose)
A lot of markup is now written by coding agents. We designed for that audience alongside humans, not as an afterthought.
What that looks like in practice:
AGENTS.md— a short curriculum for agents: reconstruct judgement in order (stems → pick-a-surface → one-part pack → maps/CI), not “dump the gallery into context.”agents/<id>.md) — Copy → exchange → DOM contract for one Hyperpart.Humans still get a pretty gallery and glossary tooltips. Agents get tables, curricula, and gates. Same Hyperpart; different entry.
This isn’t “AI-generated CSS.” It’s agent-legible architecture: restricted vocabulary, explicit contracts, fail-loud checks.
Who it’s for
hx-*at your endpoints, return HTML fragments.Standalone path is first-class: two includes, gallery copy-paste, your server.
Releases on the repo include CDN/SRI notes; gallery: https://manwithacat.github.io/hatchi-maxchi/
What I’m hoping for from this discussion
Happy to dig into dual-locks, swap/envelope vocabulary, gallery probes, or composition rules if useful — or just lurk and learn how others package hypermedia UI for teams and agents.
Thanks for reading, and thanks to everyone who keeps making hypermedia a serious alternative to “the SPA by default.”
—
Repo: https://github.com/manwithacat/hatchi-maxchi
Gallery: https://manwithacat.github.io/hatchi-maxchi/
All reactions