Hypermedia foundations

Return a full page or a fragment

Use ordinary navigation for complete documents and return focused fragments when an HTMX target needs only part of the page.

A public URL should return a complete document when opened directly. An HTMX target usually needs only the relevant fragment. Your server route should handle both cases without duplicating business logic.

One route can support both representations:

GET /tasks

if HX-History-Restore-Request is true or HX-Request is absent:
  render the full page containing that fragment
else:
  render the task-list fragment

The fragment might be:

<ul id="task-list">
  <li>Send invoice</li>
</ul>

The full response includes the document shell, title, navigation, and the same list template. Reuse the list renderer so the two paths cannot drift into different markup. I have seen teams maintain a JSON API and a separate HTML partial by hand. They always diverge. One template, two response shapes, is the safer pattern.

There is one history detail worth remembering. A request carrying HX-History-Restore-Request: true follows a cache miss and expects enough HTML to restore the page, normally a full document. Do not treat every HX-Request as an identical fragment request.

These headers describe rendering context, not identity. Any client can forge them. Never use them as authentication.

Test /tasks three ways: direct navigation in the address bar, an HTMX interaction from a button on the page, and browser back after clearing the history cache. Each response should contain the representation its consumer expects. If direct navigation shows a bare <ul> with no layout, your fragment branch is running too often.

I usually extract the fragment into a partial template and wrap it in a layout for the full page. The controller chooses which wrapper to apply based on the headers. That keeps one source of truth for the list markup itself.

Try this on your own project: open one list URL directly and through HTMX. Compare the HTML in the Network panel for both.

Lesson completed