HTMX and server-rendered fragments
Serving server-rendered HTML fragments to HTMX, and having them work with no extra wiring on either side, is the reason Oblyx exists. Everything on this page follows from that goal.
Components upgrade themselves on swap
An <oblyx-*> tag is a custom element: the browser upgrades it the moment it's in the DOM and its definition has loaded, regardless of how it got there. First paint, a client-side DOM insertion, and an HTMX swap all go through the same browser mechanism. There is no Oblyx-specific re-scan step to call after a swap, and none to remember to call: HTMX's own innerHTML-based swap already puts the new markup in the DOM, and the custom element registry does the rest on its own.
Every fragment must stand alone
HTMX routinely swaps in a fragment, a partial subtree with no enclosing parent, because a swap only ever replaces or updates its own target, never the whole page. A response that returns just the body and footer of a card, with no <oblyx-card> wrapped around them, is not an edge case to guard against. It's the normal shape of an HTMX response.
Every Oblyx child element is built to render correctly on its own for exactly this reason.<oblyx-card-body> and <oblyx-card-footer> only ever render their own light content; neither one looks for a parent <oblyx-card> to initialize, and neither needs one present to work. The example below proves it rather than asserting it: clicking the button performs a real hx-get, fetches a real file, and swaps the response into the target below with no <oblyx-card> anywhere on this page.
Fetching a card-body/card-footer fragment with no oblyx-card ancestor
This docs site is itself static, so the fetch always returns the same fixed file rather than something a server rendered per request. A real backend would branch on request state the way demo-ktor's own /signup route does; the round trip and the swap here are genuine, only the response is fixed.
Nothing fetched yet. Click the button below.
<div id="ox-fragment-target">
<p>Nothing fetched yet. Click the button below.</p>
</div>
<oblyx-button hx-get="/examples/guides/card-body-footer.html" hx-target="#ox-fragment-target" hx-swap="innerHTML">Fetch the fragment</oblyx-button>div {
id = "ox-fragment-target"
p { +"Nothing fetched yet. Click the button below." }
}
// HtmxDsl.kt in this repo defines hxPost/hxTarget/hxSwap but not yet
// hxGet, so this sets the attribute directly rather than inventing a
// helper that doesn't exist. Add an hxGet mirroring hxPost if you want
// the shorthand in your own project.
oblyxButton {
attributes["hx-get"] = "/examples/guides/card-body-footer.html"
attributes["hx-target"] = "#ox-fragment-target"
attributes["hx-swap"] = "innerHTML"
+"Fetch the fragment"
}Writing a server-rendered partial against this library, keep the same discipline in your own templates: build the piece you're returning so it renders correctly by itself, not only as part of the full page it usually appears inside. A DSL builder that only compiles when called inside a specific parent, or a component that reads state from an ancestor at render time rather than at interaction time, breaks the moment it's returned as a fragment on its own.