Log In
Get
Docs
Showcase
Community

Creating Pages and htmx Routes

In DeploySolo, a “page” is usually a normal GET route that renders a full template (e.g., todo.html). An htmx route is a route that returns partial HTML (often a single template block) to swap into the page without a full reload.

1) Register a page group and routes

Create a package in examples/<yourapp>/app/ (like todo.go) and register routes from your OnServe() hook via your app’s RegisterPages(se) (see main.go).

A typical pattern:

  • Group your feature routes (e.g., /tasks)
  • Bind auth middleware once on the group
  • Add:
    • GET "" for the full page
    • POST/PUT/DELETE for htmx actions
    • GET "/{id}" to render an “edit” partial

From the Todo example:

  • Full page: GET /tasksrenderTasksPage
  • htmx create: POST /tasks → returns one task block
  • htmx edit form: GET /tasks/{id} → returns one updatetask block
  • htmx update: PUT /tasks/{id} → returns one updated task block
  • htmx delete: DELETE /tasks/{id} → returns empty HTML to remove the row

2) Render full pages vs partial blocks

Use the render package in two modes:

  • Full page render: render.Render("todo.html", data)
    This should return a complete HTML document (your <!DOCTYPE html> template).
  • Partial render: render.RenderRaw("task", task)
    This should return only a named template block (no <html>, no <body>).

This keeps your pages clean and makes htmx swaps predictable.

3) Use htmx attributes to swap the right fragment

In templates:

  • For create: hx-post="/tasks" hx-target="#tasks" hx-swap="afterbegin"
  • For edit: hx-get="/tasks/{{ .ID }}" hx-target="#task-{{ .ID }}"
  • For update: form hx-put="/tasks/{{ .ID }}" hx-target="#task-{{ .ID }}"
  • For delete: hx-delete="/tasks/{{ .ID }}" hx-target="#task-{{ .ID }}" hx-swap="outerHTML"

Key rule: Your htmx handler must return HTML that matches the target element’s shape. If you target #task-<id>, return a single root element with id="task-<id>" so outerHTML swaps cleanly.

Tip: If you see layout “drift” after swaps, check for mismatched wrapper elements or missing classes between the view block and update block.