Demos /

HTMX fragments & forms

A coherent working example of the framework's rendering and integration contracts.

SlotKey · Slot · RenderContext · Template

Submit to replace the actual rendered values. The template is shared; request data is not.

Initial title

Supply your own request values.

Java composition
public static String typedPreview() {
    SlotKey<String> title = SlotKey.of("example.title");
    SlotKey<String> body = SlotKey.of("example.body");
    Template card = new Div().withId("template-result")
        .withChild(new HtmlTag("h3").withChild(Slot.of(title)))
        .withChild(new Paragraph().withChild(Slot.of(body))).compile();
    Form form = Form.create().withAction("/demos/api/template-card").withMethod(Form.Method.POST)
        .withHxPost("/demos/api/template-card").withHxTarget("#template-result").withHxSwap("outerHTML")
        .addField("Title", TextInput.create("title").withValue("Request-time title").required())
        .addField("Body", TextInput.create("body").withValue("A different context, the same compiled structure.").required())
        .withChild(Button.submit("Render with context"));
    return new Div().withChild(form).withChild(new RawHtml(card.render(RenderContext.builder()
        .with(title, "Initial title").with(body, "Supply your own request values.").build()))).render();
}
// POST /demos/api/template-card renders that same shared template with submitted title/body.
// The application adds CSRF fields and headers to forms before HTTP output.

Module structure & slot entries

A module builds its structure once. Live entries are escaped at render time; compiled entries accept only application-trusted rendered HTML. Both contexts reuse the same compiled module.

LiveEntry

Live <text>

CompiledEntry

Trusted compiled text

Java composition
public static String moduleEntries() {
    SlotKey<String> value = SlotKey.of("module.value");
    io.mindspice.simplypages.core.Module module = new io.mindspice.simplypages.core.Module("section") {
        protected void buildContent() {
            withChild(new Paragraph().withChild(Slot.of(value)));
        }
    };
    Template template = module.compile();
    RenderContext live = RenderContext.builder().with(value, "Live <text>").build();
    RenderContext compiled = RenderContext.builder().build()
        .putCompiled(value, new HtmlTag("strong").withInnerText("Trusted compiled text").render());
    SlotEntry liveEntry = live.getEntries().get(value);
    SlotEntry compiledEntry = compiled.getEntries().get(value);
    return new Div().withChild(new Paragraph(liveEntry.getClass().getSimpleName()))
        .withChild(new RawHtml(template.render(live)))
        .withChild(new Paragraph(compiledEntry.getClass().getSimpleName()))
        .withChild(new RawHtml(template.render(compiled))).render();
}

TemplateComponent: a bound context

This adapter intentionally ignores its parent's context. The bound value below wins over the parent's different value.

Bound value

Java composition
SlotKey<String> bound = SlotKey.of("bound");
Template view = new Paragraph().withChild(Slot.of(bound)).compile();
TemplateComponent.of(view, RenderContext.builder().with(bound, "Bound value").build())
    .render(RenderContext.builder().with(bound, "Parent value").build());

Compilation & live delegates

Custom render(RenderContext) overrides remain live delegates. A compiled view still dispatches the supplied context; sharing requires the delegate itself to be safe.

This value arrived through a live delegate

Java composition
SlotKey<String> title = SlotKey.of("example.title");
Component live = context -> new Paragraph(context.get(title).orElse("")).render(context);
Template compiled = live.compile();
compiled.render(RenderContext.builder().with(title, "This value arrived through a live delegate").build());

Forms use native POST actions and HTMX outerHTML swaps. The application supplies one hidden CSRF token and literal inherited headers. The editing example demonstrates multi-target OOB page/modal updates, including protected DELETE, validation drafts and permission failures.

Try editing and OOB updates →

Related API contracts